- Add data classes for notifications
- Add basic API for notifications - Change the password required to be a notification
This commit is contained in:
parent
e650da5278
commit
368a8da7db
7 changed files with 80 additions and 6 deletions
|
@ -271,9 +271,22 @@ class LogEntry(BaseModel):
|
||||||
metadata_json = TextField(default='{}')
|
metadata_json = TextField(default='{}')
|
||||||
|
|
||||||
|
|
||||||
|
class NotificationKind(BaseModel):
|
||||||
|
name = CharField(index=True)
|
||||||
|
|
||||||
|
|
||||||
|
class Notification(BaseModel):
|
||||||
|
uuid = CharField(default=uuid_generator, index=True)
|
||||||
|
kind = ForeignKeyField(NotificationKind, index=True)
|
||||||
|
notification_user = ForeignKeyField(User, index=True)
|
||||||
|
metadata_json = TextField(default='{}')
|
||||||
|
created = DateTimeField(default=datetime.now, index=True)
|
||||||
|
|
||||||
|
|
||||||
all_models = [User, Repository, Image, AccessToken, Role,
|
all_models = [User, Repository, Image, AccessToken, Role,
|
||||||
RepositoryPermission, Visibility, RepositoryTag,
|
RepositoryPermission, Visibility, RepositoryTag,
|
||||||
EmailConfirmation, FederatedLogin, LoginService, QueueItem,
|
EmailConfirmation, FederatedLogin, LoginService, QueueItem,
|
||||||
RepositoryBuild, Team, TeamMember, TeamRole, Webhook,
|
RepositoryBuild, Team, TeamMember, TeamRole, Webhook,
|
||||||
LogEntryKind, LogEntry, PermissionPrototype, ImageStorage,
|
LogEntryKind, LogEntry, PermissionPrototype, ImageStorage,
|
||||||
BuildTriggerService, RepositoryBuildTrigger]
|
BuildTriggerService, RepositoryBuildTrigger, NotificationKind,
|
||||||
|
Notification]
|
||||||
|
|
|
@ -93,6 +93,12 @@ def create_user(username, password, email):
|
||||||
|
|
||||||
new_user = User.create(username=username, password_hash=pw_hash,
|
new_user = User.create(username=username, password_hash=pw_hash,
|
||||||
email=email)
|
email=email)
|
||||||
|
|
||||||
|
# If the password is None, then add a notification for the user to change
|
||||||
|
# their password ASAP.
|
||||||
|
if not pw_hash:
|
||||||
|
create_notification('password_required', new_user)
|
||||||
|
|
||||||
return new_user
|
return new_user
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
raise DataModelException(ex.message)
|
raise DataModelException(ex.message)
|
||||||
|
@ -662,6 +668,9 @@ def change_password(user, new_password):
|
||||||
user.password_hash = pw_hash
|
user.password_hash = pw_hash
|
||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
|
# Remove any password required notifications for the user.
|
||||||
|
delete_notifications_by_kind(user, 'password_required')
|
||||||
|
|
||||||
|
|
||||||
def change_invoice_email(user, invoice_email):
|
def change_invoice_email(user, invoice_email):
|
||||||
user.invoice_email = invoice_email
|
user.invoice_email = invoice_email
|
||||||
|
@ -1535,3 +1544,26 @@ def list_trigger_builds(namespace_name, repository_name, trigger_uuid,
|
||||||
limit):
|
limit):
|
||||||
return (list_repository_builds(namespace_name, repository_name, limit)
|
return (list_repository_builds(namespace_name, repository_name, limit)
|
||||||
.where(RepositoryBuildTrigger.uuid == trigger_uuid))
|
.where(RepositoryBuildTrigger.uuid == trigger_uuid))
|
||||||
|
|
||||||
|
|
||||||
|
def create_notification(kind, user, metadata={}):
|
||||||
|
kind_ref = NotificationKind.get(name=kind)
|
||||||
|
notification = Notification.create(kind=kind_ref, notification_user=user,
|
||||||
|
metadata_json=json.dumps(metadata))
|
||||||
|
return notification
|
||||||
|
|
||||||
|
|
||||||
|
def list_notifications(user, kind=None):
|
||||||
|
query = (Notification.select()
|
||||||
|
.join(User)
|
||||||
|
.where(Notification.notification_user == user))
|
||||||
|
|
||||||
|
if kind:
|
||||||
|
query = query.join(NotificationKind).where(NotificationKind.name == kind)
|
||||||
|
|
||||||
|
return query.order_by(Notification.created).desc()
|
||||||
|
|
||||||
|
|
||||||
|
def delete_notifications_by_kind(user, kind):
|
||||||
|
kind_ref = NotificationKind.get(name=kind)
|
||||||
|
Notification.delete().where(Notification.user == user, Notification.kind == kind_ref).execute()
|
||||||
|
|
|
@ -28,7 +28,7 @@ from auth.permissions import (ReadRepositoryPermission,
|
||||||
ViewTeamPermission,
|
ViewTeamPermission,
|
||||||
UserPermission)
|
UserPermission)
|
||||||
from endpoints.common import (common_login, get_route_data, truthy_param,
|
from endpoints.common import (common_login, get_route_data, truthy_param,
|
||||||
start_build)
|
start_build, add_notification)
|
||||||
from endpoints.trigger import (BuildTrigger, TriggerActivationException,
|
from endpoints.trigger import (BuildTrigger, TriggerActivationException,
|
||||||
TriggerDeactivationException,
|
TriggerDeactivationException,
|
||||||
EmptyRepositoryException)
|
EmptyRepositoryException)
|
||||||
|
@ -2518,3 +2518,19 @@ def get_logs(namespace, start_time, end_time, performer_name=None,
|
||||||
'logs': [log_view(log) for log in logs]
|
'logs': [log_view(log) for log in logs]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def notification_view(notification):
|
||||||
|
return {
|
||||||
|
'kind': notification.kind.name,
|
||||||
|
'created': notification.created,
|
||||||
|
'metadata': json.loads(notification.metadata_json),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@api.route('/user/notifications', methods=['GET'])
|
||||||
|
@api_login_required
|
||||||
|
def list_user_notifications():
|
||||||
|
notifications = model.list_notifications(current_user.db_user())
|
||||||
|
return jsonify({
|
||||||
|
'notifications': [notification_view(notification) for notification in notifications]
|
||||||
|
})
|
||||||
|
|
|
@ -5,7 +5,7 @@ import urlparse
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from flask import session, make_response, render_template, request
|
from flask import session, make_response, render_template, request
|
||||||
from flask.ext.login import login_user, UserMixin
|
from flask.ext.login import login_user, UserMixin, current_user
|
||||||
from flask.ext.principal import identity_changed
|
from flask.ext.principal import identity_changed
|
||||||
|
|
||||||
from data import model
|
from data import model
|
||||||
|
@ -120,13 +120,19 @@ app.jinja_env.globals['csrf_token'] = generate_csrf_token
|
||||||
|
|
||||||
|
|
||||||
def render_page_template(name, **kwargs):
|
def render_page_template(name, **kwargs):
|
||||||
|
|
||||||
resp = make_response(render_template(name, route_data=get_route_data(),
|
resp = make_response(render_template(name, route_data=get_route_data(),
|
||||||
**kwargs))
|
**kwargs))
|
||||||
resp.headers['X-FRAME-OPTIONS'] = 'DENY'
|
resp.headers['X-FRAME-OPTIONS'] = 'DENY'
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
|
def add_notification(kind, metadata=None, user=None):
|
||||||
|
if not user and current_user:
|
||||||
|
user = current_user.db_user()
|
||||||
|
|
||||||
|
return model.create_notification(kind, user, metadata or {})
|
||||||
|
|
||||||
|
|
||||||
def start_build(repository, dockerfile_id, tags, build_name, subdir, manual,
|
def start_build(repository, dockerfile_id, tags, build_name, subdir, manual,
|
||||||
trigger=None):
|
trigger=None):
|
||||||
host = urlparse.urlparse(request.url).netloc
|
host = urlparse.urlparse(request.url).netloc
|
||||||
|
|
|
@ -203,7 +203,7 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
repo = gh_client.get_repo(source)
|
repo = gh_client.get_repo(source)
|
||||||
default_commit = repo.get_branch(repo.master_branch).commit
|
default_commit = repo.get_branch(repo.master_branch or 'master').commit
|
||||||
commit_tree = repo.get_git_tree(default_commit.sha, recursive=True)
|
commit_tree = repo.get_git_tree(default_commit.sha, recursive=True)
|
||||||
|
|
||||||
return [os.path.dirname(elem.path) for elem in commit_tree.tree
|
return [os.path.dirname(elem.path) for elem in commit_tree.tree
|
||||||
|
|
|
@ -224,6 +224,11 @@ def initialize_database():
|
||||||
LogEntryKind.create(name='setup_repo_trigger')
|
LogEntryKind.create(name='setup_repo_trigger')
|
||||||
LogEntryKind.create(name='delete_repo_trigger')
|
LogEntryKind.create(name='delete_repo_trigger')
|
||||||
|
|
||||||
|
NotificationKind.create(name='password_required')
|
||||||
|
NotificationKind.create(name='over_private_usage')
|
||||||
|
|
||||||
|
NotificationKind.create(name='test_notification')
|
||||||
|
|
||||||
|
|
||||||
def wipe_database():
|
def wipe_database():
|
||||||
logger.debug('Wiping all data from the DB.')
|
logger.debug('Wiping all data from the DB.')
|
||||||
|
@ -269,6 +274,8 @@ def populate_database():
|
||||||
outside_org.verified = True
|
outside_org.verified = True
|
||||||
outside_org.save()
|
outside_org.save()
|
||||||
|
|
||||||
|
model.create_notification('test_notification', new_user_1, metadata={'some': 'value'})
|
||||||
|
|
||||||
__generate_repository(new_user_4, 'randomrepo', 'Random repo repository.', False,
|
__generate_repository(new_user_4, 'randomrepo', 'Random repo repository.', False,
|
||||||
[], (4, [], ['latest', 'prod']))
|
[], (4, [], ['latest', 'prod']))
|
||||||
|
|
||||||
|
|
Binary file not shown.
Reference in a new issue