Skip to content

Commit

Permalink
Merge branch 'master' into pr/353
Browse files Browse the repository at this point in the history
  • Loading branch information
jace committed Jul 17, 2017
2 parents 66871fb + 478558a commit 03a9446
Show file tree
Hide file tree
Showing 119 changed files with 390 additions and 397 deletions.
5 changes: 3 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ install:
- pip install -r test_requirements.txt
- pip install -r requirements.txt
- npm install casperjs
script:
- nosetests -v tests
script: ./runtests.sh
after_success:
- coveralls
addons:
postgresql: "9.4"
services:
Expand Down
43 changes: 25 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Hasjob

Code for Hasjob, HasGeek’s job board at https://hasjob.co/

Copyright © 2010-2016 by HasGeek
Copyright © 2010-2017 by HasGeek

Hasjob’s code is open source under the AGPL v3 license (see LICENSE.txt),
but the name ‘Hasjob’ and the distinctive appearance of the job board are
Expand All @@ -24,11 +24,20 @@ To have your contributions merged back into the master repository, you must
agree to assign copyright to HasGeek and must assert that you have
the right to make this assignment.

-----
## Installation

Hasjob can be used with Docker (recommended for quick start) or the harder way with a manual setup (recommended for getting involved).
Hasjob can be used with Docker (recommended for quick start) or the harder way with a manual setup (recommended for getting involved). The Docker approach is unmaintained at this time. Let us know if something doesn't work.

## With Docker
### Pick an environment

Hasjob requires a `FLASK_ENV` environment variable set to one of the following values, depending on whether the deployment is in development or production:

* `DEVELOPMENT` or `development` or `dev` (default)
* `PRODUCTION` or `production` or `prod`

In a production environment, you must set `FLASK_ENV` globally for it to be available across processes. On Ubuntu/Debian systems, add it to `/etc/environment` and reboot.

### With Docker

#### Install and run with Docker

Expand Down Expand Up @@ -58,11 +67,11 @@ Hasjob can be used with Docker (recommended for quick start) or the harder way w
* You can edit the server name and Lastuser settings in `docker-compose.yml`
## Without Docker
### Without Docker
Hasjob without Docker requires manual installation of all dependencies.
### Postgres and Redis
#### Postgres and Redis
Hasjob requires Postgres >= 9.4 and Redis. To set up a Postgres DB:
Expand All @@ -83,7 +92,7 @@ Edit `instance/development.py` to set the variable `SQLALCHEMY_DATABASE_URI` to
Redis does not require special configuration, but must listen on localhost and port 6379 (default).
### Local URLs
#### Local URLs
Hasjob makes use of subdomains to serve different sub-boards for jobs. To set it up:
Expand All @@ -97,11 +106,11 @@ Hasjob makes use of subdomains to serve different sub-boards for jobs. To set it
* Edit `instance/development.py` and change `SERVER_NAME` to `'hasjob.your-machine.local:5000'`
### Install dependencies
#### Install dependencies
Hasjob runs on [Python](https://www.python.org) with the [Flask](http://flask.pocoo.org/) microframework.
#### Virutalenv + pip
##### Virutalenv + pip
If you are going to use a computer on which you would work on multiple Python based projects, [Virtualenv](docs.python-guide.org/en/latest/dev/virtualenvs/) is strongly recommended to ensure Hasjob’s elaborate and sometimes version-specific requirements doesn't clash with anything else.
Expand All @@ -127,20 +136,18 @@ Before you run the server in development mode, make sure you have Postgres serve
$ python runserver.py
## Create root board
### Create root board
Some functionality in Hasjob requires the presence of a sub-board named `www`. Create it by visiting `http://hasjob.your-machine.local:5000/board` (or the `/board` page on whatever hostname and port you used for your installation). The `www` board is a special-case to refer to the root website.
## Periodic jobs
### Periodic jobs
Hasjob requires some tasks to be run in periodic background jobs. These can be called from cron. Use `crontab -e` as the user account running Hasjob and add:
*/10 * * * * cd /path/to/hasjob; python manage.py periodic sessions -e dev
*/5 * * * * cd /path/to/hasjob; python manage.py periodic impressions -e dev
Switch from `dev` to `production` in a production environment.
*/10 * * * * cd /path/to/hasjob; python manage.py periodic sessions
*/5 * * * * cd /path/to/hasjob; python manage.py periodic impressions
## Testing
### Testing
Tests are outdated at this time, but whatever tests exist are written in [CasperJS](http://casperjs.org/).
Expand All @@ -150,14 +157,14 @@ Edit the top few lines of test file `tests/test_job_post.js` with the URL, usern
Run the test with `casperjs test tests/test_job_post.js`.
## Disabling Cache
### Disabling Cache
If you ever want to disable caching when developing, inside your `development.py`, add these lines -
CACHE_TYPE = 'null'
CACHE_NO_NULL_WARNING = False
## Other notes
### Other notes
If you encounter a problem setting up, please look at existing issue reports
on GitHub before filing a new issue. This code is the same version used in
Expand Down
45 changes: 0 additions & 45 deletions alembic/versions/472ca8e93765_boards.py

This file was deleted.

40 changes: 0 additions & 40 deletions alembic/versions/95eacca1a9d_jobapps.py

This file was deleted.

69 changes: 34 additions & 35 deletions hasjob/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
import os.path
import geoip2.database
from flask import Flask
from flask.ext.assets import Bundle
from flask.ext.rq import RQ
from flask.ext.mail import Mail
from flask.ext.redis import Redis
from flask.ext.lastuser import Lastuser
from flask.ext.lastuser.sqlalchemy import UserManager
from flask_migrate import Migrate
from flask_assets import Bundle
from flask_rq import RQ
from flask_mail import Mail
from flask_redis import FlaskRedis
from flask_lastuser import Lastuser
from flask_lastuser.sqlalchemy import UserManager
from baseframe import baseframe, assets, Version
import coaster.app
from ._version import __version__
Expand All @@ -20,7 +21,7 @@
app.static_folder = 'static'
mail = Mail()
lastuser = Lastuser()
redis_store = Redis()
redis_store = FlaskRedis()

# Second, setup assets
version = Version(__version__)
Expand All @@ -32,35 +33,33 @@
from . import models, views # NOQA
from .models import db # NOQA


# Configure the app
def init_for(env):
coaster.app.init_app(app, env)
db.init_app(app)
db.app = app

app.geoip = None
if 'GEOIP_PATH' in app.config:
if not os.path.exists(app.config['GEOIP_PATH']):
app.logger.warn("GeoIP database missing at " + app.config['GEOIP_PATH'])
else:
app.geoip = geoip2.database.Reader(app.config['GEOIP_PATH'])
coaster.app.init_app(app)
db.init_app(app)
db.app = app
migrate = Migrate(app, db)
app.geoip = None
if 'GEOIP_PATH' in app.config:
if not os.path.exists(app.config['GEOIP_PATH']):
app.logger.warn("GeoIP database missing at " + app.config['GEOIP_PATH'])
else:
app.geoip = geoip2.database.Reader(app.config['GEOIP_PATH'])

RQ(app)
RQ(app)

baseframe.init_app(app, requires=['hasjob'],
ext_requires=['baseframe-bs3',
('jquery.autosize', 'jquery.sparkline', 'jquery.liblink', 'jquery.wnumb', 'jquery.nouislider'),
'baseframe-firasans', 'fontawesome>=4.3.0', 'bootstrap-multiselect', 'nprogress', 'ractive',
'jquery.appear', 'hammer'])
# TinyMCE has to be loaded by itself, unminified, or it won't be able to find its assets
app.assets.register('js_tinymce', assets.require('!jquery.js', 'tinymce.js>=4.0.0', 'jquery.tinymce.js>=4.0.0'))
app.assets.register('css_editor', Bundle('css/editor.css',
filters=['cssrewrite', 'cssmin'], output='css/editor.packed.css'))
baseframe.init_app(app, requires=['hasjob'],
ext_requires=['baseframe-bs3',
('jquery.autosize', 'jquery.sparkline', 'jquery.liblink', 'jquery.wnumb', 'jquery.nouislider'),
'baseframe-firasans', 'fontawesome>=4.3.0', 'bootstrap-multiselect', 'nprogress', 'ractive',
'jquery.appear', 'hammer'])
# TinyMCE has to be loaded by itself, unminified, or it won't be able to find its assets
app.assets.register('js_tinymce', assets.require('!jquery.js', 'tinymce.js>=4.0.0', 'jquery.tinymce.js>=4.0.0'))
app.assets.register('css_editor', Bundle('css/editor.css',
filters=['cssrewrite', 'cssmin'], output='css/editor.packed.css'))

from hasjob.uploads import configure as uploads_configure
uploads_configure()
mail.init_app(app)
redis_store.init_app(app)
lastuser.init_app(app)
lastuser.init_usermanager(UserManager(db, models.User))
from hasjob.uploads import configure as uploads_configure
uploads_configure()
mail.init_app(app)
redis_store.init_app(app)
lastuser.init_app(app)
lastuser.init_usermanager(UserManager(db, models.User))
26 changes: 14 additions & 12 deletions hasjob/forms/board.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ class BoardOptionsForm(forms.Form):
description=__(u"Hasjob requires employers to reveal what they intend to pay, "
u"but you can make it optional for jobs posted from this board. "
u"Pay data is used to match candidates to jobs. We recommend you collect it"))
newjob_headline = forms.NullTextField(__(u"Headline"),
newjob_headline = forms.StringField(__(u"Headline"),
description=__(u"Optional – The sample headline shown to employers when posting a job"),
validators=[
forms.validators.StripWhitespace(),
forms.validators.Length(min=0, max=100, message=__("%%(max)d characters maximum"))])
forms.validators.Length(min=0, max=100, message=__("%%(max)d characters maximum"))],
filters=[forms.filters.strip(), forms.filters.none_if_empty()])
newjob_blurb = forms.TinyMce4Field(__(u"Posting instructions"),
description=__(u"Optional – What should we tell employers when they post a job on your board? "
u"Leave blank to use the default text"),
Expand Down Expand Up @@ -109,15 +109,17 @@ class BoardForm(forms.Form):
"""
Edit board settings.
"""
title = forms.StringField(__("Title"), validators=[
forms.validators.DataRequired(__("The board needs a name")),
forms.validators.StripWhitespace(),
forms.validators.Length(min=1, max=80, message=__("%%(max)d characters maximum"))])
caption = forms.NullTextField(__("Caption"), validators=[
forms.validators.Optional(),
forms.validators.StripWhitespace(),
forms.validators.Length(min=0, max=80, message=__("%%(max)d characters maximum"))],
description=__("The title and caption appear at the top of the page. Keep them concise"))
title = forms.StringField(__("Title"),
validators=[
forms.validators.DataRequired(__("The board needs a name")),
forms.validators.Length(min=1, max=80, message=__("%%(max)d characters maximum"))],
filters=[forms.filters.strip()])
caption = forms.StringField(__("Caption"),
description=__("The title and caption appear at the top of the page. Keep them concise"),
validators=[
forms.validators.Optional(),
forms.validators.Length(min=0, max=80, message=__("%%(max)d characters maximum"))],
filters=[forms.filters.strip(), forms.filters.none_if_empty()])
name = forms.AnnotatedTextField(__("URL Name"), prefix='https://', suffix=u'.hasjob.co',
description=__(u"Optional — Will be autogenerated if blank"),
validators=[
Expand Down
Loading

0 comments on commit 03a9446

Please sign in to comment.