Skip to content

Commit 93e8337

Browse files
authored
Merge branch 'master' into custom_select
2 parents f0db61b + 6aab559 commit 93e8337

File tree

17 files changed

+206
-67
lines changed

17 files changed

+206
-67
lines changed

.codeclimate.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
engines:
33
csslint:
4-
enabled: true
4+
enabled: false
55
duplication:
66
enabled: true
77
config:
@@ -24,3 +24,7 @@ ratings:
2424
- "**.py"
2525
exclude_paths:
2626
- app/static/*
27+
checks:
28+
argument-count:
29+
config:
30+
threshold: 6

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ webassets-external/
55
*.pyo
66
env
77
venv
8-
.env
8+
*.env
99
env*
1010
dist
1111
*.egg
1212
*.egg-info
1313
*.sqlite
1414
.idea
1515
dump.rdb
16+
.vscode/

CODE_OF_CONDUCT.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Contributor Covenant Code of Conduct
2+
3+
## Our Pledge
4+
5+
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6+
7+
## Our Standards
8+
9+
Examples of behavior that contributes to creating a positive environment include:
10+
11+
* Using welcoming and inclusive language
12+
* Being respectful of differing viewpoints and experiences
13+
* Gracefully accepting constructive criticism
14+
* Focusing on what is best for the community
15+
* Showing empathy towards other community members
16+
17+
Examples of unacceptable behavior by participants include:
18+
19+
* The use of sexualized language or imagery and unwelcome sexual attention or advances
20+
* Trolling, insulting/derogatory comments, and personal or political attacks
21+
* Public or private harassment
22+
* Publishing others' private information, such as a physical or electronic address, without explicit permission
23+
* Other conduct which could reasonably be considered inappropriate in a professional setting
24+
25+
## Our Responsibilities
26+
27+
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28+
29+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30+
31+
## Scope
32+
33+
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34+
35+
## Enforcement
36+
37+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [email protected]. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38+
39+
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40+
41+
## Attribution
42+
43+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44+
45+
[homepage]: http://contributor-covenant.org
46+
[version]: http://contributor-covenant.org/version/1/4/

README.md

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
# flask-base
2-
[![Circle CI](https://circleci.com/gh/hack4impact/flask-base.svg?style=svg)](https://circleci.com/gh/hack4impact/flask-base) [![Stories in Ready](https://badge.waffle.io/hack4impact/flask-base.png?label=ready&title=Ready)](https://waffle.io/hack4impact/flask-base)
3-
[![Code Climate](https://codeclimate.com/github/hack4impact/flask-base/badges/gpa.svg)](https://codeclimate.com/github/hack4impact/flask-base/coverage)
1+
# flask-base
2+
[![Circle CI](https://circleci.com/gh/hack4impact/flask-base.svg?style=svg)](https://circleci.com/gh/hack4impact/flask-base) [![Stories in Ready](https://badge.waffle.io/hack4impact/flask-base.png?label=ready&title=Ready)](https://waffle.io/hack4impact/flask-base)
3+
[![Code Climate](https://codeclimate.com/github/hack4impact/flask-base/badges/gpa.svg)](https://codeclimate.com/github/hack4impact/flask-base/coverage)
44
[![Issue Count](https://codeclimate.com/github/hack4impact/flask-base/badges/issue_count.svg)](https://codeclimate.com/github/hack4impact/flask-base) ![python3.x](https://img.shields.io/badge/python-3.x-brightgreen.svg) ![python2.x](https://img.shields.io/badge/python-2.x-yellow.svg)
5-
<img src="readme_media/[email protected]" width="400"/>
5+
6+
![flask-base](readme_media/logo.png)
67

78
A Flask application template with the boilerplate code already done for you.
89

@@ -19,22 +20,22 @@ A Flask application template with the boilerplate code already done for you.
1920
* Flask-Mail for sending emails
2021
* gzip compression
2122
* Redis Queue for handling asynchronous tasks
22-
* ZXCVBN password strength checker
23+
* ZXCVBN password strength checker
2324
* CKEditor for editing pages
2425

2526
## Demos
2627

2728
Home Page:
2829

29-
![home](readme_media/home.gif "home")
30+
![home](readme_media/home.gif "home")
3031

3132
Registering User:
3233

3334
![registering](readme_media/register.gif "register")
3435

3536
Admin Editing Page:
3637

37-
![edit page](readme_media/editpage.gif "editpage")
38+
![edit page](readme_media/editpage.gif "editpage")
3839

3940
Admin Editing Users:
4041

@@ -72,10 +73,12 @@ Note: if you are using a python2.x version, point the -p value towards your pyth
7273
$ xcode-select --install
7374
```
7475

75-
##### Add Environment Variables
76+
##### Add Environment Variables
7677

77-
Create a file called `config.env` that contains environment variables in the following syntax: `ENVIRONMENT_VARIABLE=value`. For example,
78-
the mailing environment variables can be set as the following. We recommend using Sendgrid for a mailing SMTP server. But anything else will work as well.
78+
Create a file called `config.env` that contains environment variables in the following syntax: `ENVIRONMENT_VARIABLE=value`.
79+
You may also wrap values in double quotes like `ENVIRONMENT_VARIABLE="value with spaces"`.
80+
For example, the mailing environment variables can be set as the following.
81+
We recommend using Sendgrid for a mailing SMTP server, but anything else will work as well.
7982

8083
```
8184
MAIL_USERNAME=SendgridUsername
@@ -90,7 +93,7 @@ Other Key value pairs:
9093
* `DATABASE_URL`: set to a postgresql database url (default is `data-dev.sqlite`)
9194
* `REDISTOGO_URL`: set to Redis To Go URL or any redis server url (default is `http://localhost:6379`)
9295
* `RAYGUN_APIKEY`: api key for raygun (default is `None`)
93-
* `FLASK_CONFIG`: can be `development`, `production`, `default`, `heroku`, `unix`, or `testing`. Most of the time you will use `development` or `production`.
96+
* `FLASK_CONFIG`: can be `development`, `production`, `default`, `heroku`, `unix`, or `testing`. Most of the time you will use `development` or `production`.
9497

9598

9699
**Note: do not include the `config.env` file in any commits. This should remain private.**
@@ -181,9 +184,9 @@ Contributions are welcome! Check out our [Waffle board](https://waffle.io/hack4i
181184

182185
## Documentation Changes
183186

184-
To make changes to the documentation refer to the [Mkdocs documentation](http://www.mkdocs.org/#installation) for setup.
187+
To make changes to the documentation refer to the [Mkdocs documentation](http://www.mkdocs.org/#installation) for setup.
185188

186-
To create a new documentation page, add a file to the `docs/` directory and edit `mkdocs.yml` to reference the file.
189+
To create a new documentation page, add a file to the `docs/` directory and edit `mkdocs.yml` to reference the file.
187190

188191
When the new files are merged into `master` and pushed to github. Run `mkdocs gh-deploy` to update the online documentation.
189192

app.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
},
77
"env": {
88
"FLASK_CONFIG": {
9-
"required": true
9+
"value": "production"
1010
},
1111
"SECRET_KEY": {
1212
"generator": "secret"
@@ -19,6 +19,12 @@
1919
}
2020
},
2121
"formation": {
22+
"web": {
23+
"quantity": 1
24+
},
25+
"worker": {
26+
"quantity": 1
27+
}
2228
},
2329
"addons": [
2430
"heroku-postgresql",

app/account/forms.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,46 @@
1111

1212
class LoginForm(Form):
1313
email = EmailField(
14-
'Email', validators=[InputRequired(), Length(1, 64), Email()])
14+
'Email', validators=[InputRequired(),
15+
Length(1, 64),
16+
Email()])
1517
password = PasswordField('Password', validators=[InputRequired()])
1618
remember_me = BooleanField('Keep me logged in')
1719
submit = SubmitField('Log in')
1820

1921

2022
class RegistrationForm(Form):
2123
first_name = StringField(
22-
'First name', validators=[InputRequired(), Length(1, 64)])
24+
'First name', validators=[InputRequired(),
25+
Length(1, 64)])
2326
last_name = StringField(
24-
'Last name', validators=[InputRequired(), Length(1, 64)])
27+
'Last name', validators=[InputRequired(),
28+
Length(1, 64)])
2529
email = EmailField(
26-
'Email', validators=[InputRequired(), Length(1, 64), Email()])
30+
'Email', validators=[InputRequired(),
31+
Length(1, 64),
32+
Email()])
2733
password = PasswordField(
2834
'Password',
2935
validators=[
30-
InputRequired(), EqualTo('password2', 'Passwords must match')
36+
InputRequired(),
37+
EqualTo('password2', 'Passwords must match')
3138
])
3239
password2 = PasswordField('Confirm password', validators=[InputRequired()])
3340
submit = SubmitField('Register')
3441

3542
def validate_email(self, field):
3643
if User.query.filter_by(email=field.data).first():
3744
raise ValidationError('Email already registered. (Did you mean to '
38-
'<a href="{}">log in</a> instead?)'
39-
.format(url_for('account.login')))
45+
'<a href="{}">log in</a> instead?)'.format(
46+
url_for('account.login')))
4047

4148

4249
class RequestResetPasswordForm(Form):
4350
email = EmailField(
44-
'Email', validators=[InputRequired(), Length(1, 64), Email()])
51+
'Email', validators=[InputRequired(),
52+
Length(1, 64),
53+
Email()])
4554
submit = SubmitField('Reset password')
4655

4756
# We don't validate the email address so we don't confirm to attackers
@@ -50,11 +59,14 @@ class RequestResetPasswordForm(Form):
5059

5160
class ResetPasswordForm(Form):
5261
email = EmailField(
53-
'Email', validators=[InputRequired(), Length(1, 64), Email()])
62+
'Email', validators=[InputRequired(),
63+
Length(1, 64),
64+
Email()])
5465
new_password = PasswordField(
5566
'New password',
5667
validators=[
57-
InputRequired(), EqualTo('new_password2', 'Passwords must match.')
68+
InputRequired(),
69+
EqualTo('new_password2', 'Passwords must match.')
5870
])
5971
new_password2 = PasswordField(
6072
'Confirm new password', validators=[InputRequired()])
@@ -69,7 +81,8 @@ class CreatePasswordForm(Form):
6981
password = PasswordField(
7082
'Password',
7183
validators=[
72-
InputRequired(), EqualTo('password2', 'Passwords must match.')
84+
InputRequired(),
85+
EqualTo('password2', 'Passwords must match.')
7386
])
7487
password2 = PasswordField(
7588
'Confirm new password', validators=[InputRequired()])
@@ -81,7 +94,8 @@ class ChangePasswordForm(Form):
8194
new_password = PasswordField(
8295
'New password',
8396
validators=[
84-
InputRequired(), EqualTo('new_password2', 'Passwords must match.')
97+
InputRequired(),
98+
EqualTo('new_password2', 'Passwords must match.')
8599
])
86100
new_password2 = PasswordField(
87101
'Confirm new password', validators=[InputRequired()])
@@ -90,7 +104,9 @@ class ChangePasswordForm(Form):
90104

91105
class ChangeEmailForm(Form):
92106
email = EmailField(
93-
'New email', validators=[InputRequired(), Length(1, 64), Email()])
107+
'New email', validators=[InputRequired(),
108+
Length(1, 64),
109+
Email()])
94110
password = PasswordField('Password', validators=[InputRequired()])
95111
submit = SubmitField('Update email')
96112

app/account/views.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from flask import flash, redirect, render_template, request, url_for
2-
from flask_login import (current_user, login_required, login_user,
3-
logout_user)
2+
from flask_login import current_user, login_required, login_user, logout_user
43
from flask_rq import get_queue
54

65
from . import account
@@ -91,8 +90,8 @@ def reset_password_request():
9190
user=user,
9291
reset_link=reset_link,
9392
next=request.args.get('next'))
94-
flash('A password reset link has been sent to {}.'
95-
.format(form.email.data), 'warning')
93+
flash('A password reset link has been sent to {}.'.format(
94+
form.email.data), 'warning')
9695
return redirect(url_for('account.login'))
9796
return render_template('account/reset_password.html', form=form)
9897

app/admin/forms.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111

1212
class ChangeUserEmailForm(Form):
1313
email = EmailField(
14-
'New email', validators=[InputRequired(), Length(1, 64), Email()])
14+
'New email', validators=[InputRequired(),
15+
Length(1, 64),
16+
Email()])
1517
submit = SubmitField('Update email')
1618

1719
def validate_email(self, field):
@@ -35,11 +37,15 @@ class InviteUserForm(Form):
3537
get_label='name',
3638
query_factory=lambda: db.session.query(Role).order_by('permissions'))
3739
first_name = StringField(
38-
'First name', validators=[InputRequired(), Length(1, 64)])
40+
'First name', validators=[InputRequired(),
41+
Length(1, 64)])
3942
last_name = StringField(
40-
'Last name', validators=[InputRequired(), Length(1, 64)])
43+
'Last name', validators=[InputRequired(),
44+
Length(1, 64)])
4145
email = EmailField(
42-
'Email', validators=[InputRequired(), Length(1, 64), Email()])
46+
'Email', validators=[InputRequired(),
47+
Length(1, 64),
48+
Email()])
4349
submit = SubmitField('Invite')
4450

4551
def validate_email(self, field):
@@ -51,7 +57,8 @@ class NewUserForm(InviteUserForm):
5157
password = PasswordField(
5258
'Password',
5359
validators=[
54-
InputRequired(), EqualTo('password2', 'Passwords must match.')
60+
InputRequired(),
61+
EqualTo('password2', 'Passwords must match.')
5562
])
5663
password2 = PasswordField('Confirm password', validators=[InputRequired()])
5764

app/admin/views.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
from flask import abort, flash, redirect, render_template, url_for, request
1+
from flask import abort, flash, redirect, render_template, request, url_for
22
from flask_login import current_user, login_required
33
from flask_rq import get_queue
44

5-
from .forms import (ChangeAccountTypeForm, ChangeUserEmailForm, InviteUserForm,
6-
NewUserForm)
75
from . import admin
86
from .. import db
97
from ..decorators import admin_required
108
from ..email import send_email
11-
from ..models import Role, User, EditableHTML
9+
from ..models import EditableHTML, Role, User
10+
from .forms import (ChangeAccountTypeForm, ChangeUserEmailForm, InviteUserForm,
11+
NewUserForm)
1212

1313

1414
@admin.route('/')
@@ -65,7 +65,8 @@ def invite_user():
6565
subject='You Are Invited To Join',
6666
template='account/email/invite',
6767
user=user,
68-
invite_link=invite_link, )
68+
invite_link=invite_link,
69+
)
6970
flash('User {} successfully invited'.format(user.full_name()),
7071
'form-success')
7172
return render_template('admin/new_user.html', form=form)
@@ -107,8 +108,8 @@ def change_user_email(user_id):
107108
user.email = form.email.data
108109
db.session.add(user)
109110
db.session.commit()
110-
flash('Email for user {} successfully changed to {}.'
111-
.format(user.full_name(), user.email), 'form-success')
111+
flash('Email for user {} successfully changed to {}.'.format(
112+
user.full_name(), user.email), 'form-success')
112113
return render_template('admin/manage_user.html', user=user, form=form)
113114

114115

@@ -131,8 +132,8 @@ def change_account_type(user_id):
131132
user.role = form.role.data
132133
db.session.add(user)
133134
db.session.commit()
134-
flash('Role for user {} successfully changed to {}.'
135-
.format(user.full_name(), user.role.name), 'form-success')
135+
flash('Role for user {} successfully changed to {}.'.format(
136+
user.full_name(), user.role.name), 'form-success')
136137
return render_template('admin/manage_user.html', user=user, form=form)
137138

138139

0 commit comments

Comments
 (0)