Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup #41

Merged
merged 52 commits into from
Apr 20, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
7d98e57
editable userrole by ferdinand and invitation&application logic
OleKet Jun 12, 2018
0a7b408
removing db from app
3j14 Jun 13, 2018
a244503
Merge branch 'master' of github.com:Info-ag/labplaner into dev
3j14 Jun 14, 2018
210d285
cleanup
3j14 Jun 14, 2018
4d1ade2
adding success
3j14 Jun 14, 2018
07c2523
adding remember me
3j14 Jun 14, 2018
e21b7c2
remember me button
OleKet Jun 14, 2018
9c1c320
completed test
3j14 Jun 14, 2018
6b334c3
adding email confirmation
3j14 Jun 14, 2018
6d6c35a
message Feature for AGs & with email when email is confirmed
OleKet Jun 15, 2018
2677f7e
removed useless prints. replaced double quotes with single quotes
OleKet Jun 15, 2018
4a816b5
pylint comments, module doc string, splitting ag_api and utils
OleKet Jun 15, 2018
6009106
adding docstrings and comments
OleKet Jun 16, 2018
400d658
changing docstrings
3j14 Jun 24, 2018
4e0123a
Adding huey starter
3j14 Feb 1, 2019
b8db869
Set up run for future use
3j14 Feb 1, 2019
4b7a811
rename utils to util
3j14 Feb 1, 2019
c16a06c
add huey tasks
3j14 Feb 1, 2019
45ee1ad
Removing unnecessary junk
3j14 Apr 6, 2019
db893f3
delete unused files
3j14 Apr 11, 2019
a122aa4
add config
3j14 Apr 11, 2019
ccf85e8
add tests
3j14 Apr 11, 2019
2c83c1e
add manage script
3j14 Apr 11, 2019
4d2fe75
rename file
3j14 Apr 11, 2019
cacb5d4
add i18n
3j14 Apr 11, 2019
a7b5cf2
move messages to extra file
3j14 Apr 11, 2019
b3e4acb
remove unnecessary files
3j14 Apr 11, 2019
b16d438
add function to create app and db
3j14 Apr 11, 2019
d7f5083
fix permissions
3j14 Apr 11, 2019
a91f7fc
add os to gitignore
3j14 Apr 11, 2019
f714814
add new dependencies
3j14 Apr 11, 2019
168b98e
add versions
3j14 Apr 11, 2019
912ca09
rename utils -> util
3j14 Apr 11, 2019
2f8b18b
pep8 stuff
3j14 Apr 11, 2019
acefac9
fix event model
3j14 Apr 11, 2019
31d54ec
clean up comments
3j14 Apr 11, 2019
4903dbd
fix date model
3j14 Apr 11, 2019
ef0562d
fix ag model
3j14 Apr 11, 2019
6766d90
update readme
3j14 Apr 11, 2019
a20bfd0
add new test routines
3j14 Apr 11, 2019
a87b9f2
use assertEqual instead of keyword
3j14 Apr 11, 2019
e9d2e6f
add style guide
3j14 Apr 11, 2019
5689995
rewrite comment
3j14 Apr 11, 2019
d4d9003
add redis session
3j14 Apr 11, 2019
49c3642
fix comment
3j14 Apr 11, 2019
2fdc7b5
. instead of :
3j14 Apr 11, 2019
d63918e
add babel
3j14 Apr 11, 2019
e777fe5
add session
3j14 Apr 11, 2019
9325fa2
fix redis session
3j14 Apr 11, 2019
3ed6f01
fix comments
3j14 Apr 11, 2019
5485f51
who needs pizza
3j14 Apr 11, 2019
af0aa34
fix lines
3j14 Apr 11, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
message Feature for AGs & with email when email is confirmed
  • Loading branch information
OleKet committed Jun 15, 2018
commit 6d6c35abf199db9773e08d22719c32062c5ddfab
6 changes: 5 additions & 1 deletion app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
ma = Marshmallow(app)

from app.models.user import Session, User
from app.models.ag import AG, AGSchema
from app.models.associations import UserAG
from app.utils import after_this_request, requires_auth

from app.blueprints.api import v1
Expand Down Expand Up @@ -89,4 +91,6 @@ def set_cookie(response):
@app.route('/')
@requires_auth()
def index():
return render_template('index.html', title='Dashboard')
ags = db.session.query(AG).join(UserAG).filter(UserAG.user_id == g.session.user_id)
ags_schema = AGSchema(many=True)
return render_template('index.html', title='Dashboard', ags=ags_schema.dump(ags))
27 changes: 22 additions & 5 deletions app/blueprints/ag.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from flask import Blueprint, g, redirect, render_template, url_for, flash
from sqlalchemy.sql import exists
from werkzeug.exceptions import NotFound, Unauthorized
from app.models.associations import UserAG
from app.models.ag import AG, AGSchema, AGSchemaIntern
from app.models.associations import UserAG, UserAGMessage
from app.models.ag import AG, AGSchema, AGSchemaIntern, AGMessage, AGMessageSchema
from app.models import db
from app.utils import requires_auth, requires_mentor, requires_membership
from app.utils import requires_auth, requires_mentor, requires_membership, requires_ag_message_rights

from config.regex import AGRegex
from config.regex import AGRegex, MessageRegex

bp = Blueprint('ag', __name__)

Expand Down Expand Up @@ -65,4 +65,21 @@ def discover():
@requires_auth()
@requires_mentor()
def edit_event():
pass
pass

@bp.route('<ag_name>/messages/write', methods=["GET"])
@requires_auth()
@requires_mentor()
def write_message(ag_name, ag, user_ag):
print(ag_name)
return render_template('ag/write_message.html', title=f"Write Message for {ag.display_name}", message_regex=MessageRegex, ag_name=ag_name)

@bp.route('<ag_name>/messages/view/<message_id>')
@requires_auth()
@requires_ag_message_rights()
def view_message(ag_name, message_id, ag, user_ag, ag_message, user_ag_message):
message_schema = AGMessageSchema()
user_ag_message.read = True
db.session.add(user_ag_message)
db.session.commit()
return render_template('ag/view_message.html', title='View Message', message=message_schema.dump(ag_message), my_role=user_ag.role)
76 changes: 71 additions & 5 deletions app/blueprints/api/v1/ag.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
from sqlalchemy.sql import exists, and_, or_
from werkzeug.exceptions import NotFound, BadRequest, Forbidden, PreconditionFailed

from app.models.ag import AG, AGSchema, AGSchemaIntern
from app.models.ag import AG, AGSchema, AGSchemaIntern, AGMessage
from app.models.user import User, UserSchema
from app.models.associations import UserAG
from app.models.associations import UserAG, UserAGMessage
from app.models import db

from app.utils import requires_auth, requires_mentor, requires_ag, requires_member_association, requires_gracefully_not_member, get_user_by_username, get_membership
from app.utils import requires_auth, requires_mentor, requires_ag, requires_member_association, requires_gracefully_not_member, get_user_by_username, get_membership, get_user_by_username

from config.regex import AGRegex
from config.regex import AGRegex, MessageRegex
import app.mail as mail

bp = Blueprint('ag_api', __name__)

Expand All @@ -25,7 +26,7 @@
@requires_auth()
def add_ag():
'''
Create a new AG. The request body has to inclurde the following:
Create a new AG. The request body has to include the following:
:key: name: AG name used to identify the ag (eg. /ag/<name>)
:key: display_name: AG name that is human read able
(can contain spaces etc.)
Expand Down Expand Up @@ -338,3 +339,68 @@ def leave_ag(ag_name, ag, user_ag):
flash(f'You sucessfully left the AG {ag.name}', 'success')
db.session.commit()
return redirect(url_for('index'))



@bp.route('<ag_name>/kick/<user_name>')
@requires_auth()
@requires_mentor()
def kick_user(ag_name, user_name, ag, user_ag):

user = get_user_by_username(user_name)
edit_user_ag = db.session.query(UserAG).filter_by(user_id=user.id, ag_id=ag.id).scalar()
if(edit_user_ag is None or edit_user_ag.role == "NONE"):
flash(f'You cannot kick {user.username} from {ag.display_name}. He is no valid member of this AG')
return redirect(url_for('ag.ag_dashboard', ag_name=ag_name))
edit_user_ag.role = "NONE"
edit_user_ag.status = "KICKED"
db.session.flush()
if(len(ag.actual_users) == 0):
db.session.delete(ag)
db.session.commit()
flash(f'You sucessfully left and deleted the AG {ag.display_name}', 'success')
return redirect(url_for('index'))
elif(len(ag.mentors) == 0):
flash(f'You cannot kick the last Mentor of {ag.display_name}', 'error')
else:
flash(f'You sucessfully kicked {user.username} from the AG {ag.display_name}', 'success')
db.session.commit()
return redirect(url_for('ag.ag_dashboard', ag_name=ag_name))

@bp.route('<ag_name>/delete')
@requires_auth()
@requires_mentor()
def delete_ag(ag_name, ag, user_ag):
db.session.delete(ag)
db.session.commit()
flash(f'You successfully deleted the AG {ag.display_name}', 'success')
return redirect(url_for('index'))

@bp.route('<ag_name>/messages/write', methods=["POST"])
@requires_auth()
@requires_mentor()
def write_message(ag_name, ag, user_ag):
subject = request.values.get('subject')
message = request.values.get('message')
email = request.values.get('email')
if subject is None and not bool(re.match(MessageRegex.subject, subject)):
return PreconditionFailed(description='subject')
if message is None and not bool(re.match(MessageRegex.message, message)):
return PreconditionFailed(description='message')
new_message = AGMessage()
new_message.subject = subject
new_message.message = message
new_message.ag_id = ag.id
db.session.add(new_message)
db.session.flush()
for user in ag.actual_users:
new_assoc = UserAGMessage()
new_assoc.user_id = user.id
new_assoc.message_id = new_message.id
new_assoc.read = False
db.session.add(new_assoc)
if email is not None:
mail.ag_mail(agmessage=new_message, ag=ag)
db.session.commit()
flash('Successfully send message', 'success')
return redirect(url_for('ag.ag_dashboard', ag_name=ag_name))
3 changes: 1 addition & 2 deletions app/blueprints/api/v1/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,8 @@ def add_user():

db.session.add(user)
db.session.commit()

mail.confirmation_mail(user)

return user_schema.jsonify(user), 200
except Exception as e:
print(e)
Expand Down
9 changes: 8 additions & 1 deletion app/mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from flask_mail import Mail, Message

from app.models.user import User

from app.models.ag import AGMessage, AG
mail = Mail()


Expand All @@ -12,3 +12,10 @@ def confirmation_mail(user: User):
)
message.add_recipient(user.email)
mail.send(message)

def ag_mail(agmessage: AGMessage, ag: AG):
message = Message(subject=agmessage.subject, body=agmessage.message)
for user in ag.actual_users:
if user.email_confirmed:
message.add_recipient(user.email)
mail.send(message)
89 changes: 87 additions & 2 deletions app/models/ag.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from app import ma
from app.models import db
from sqlalchemy import and_
from app.models.associations import UserAG
from app.models.associations import UserAG, UserAGMessage, UserAGMessageSchema
from flask import g
from datetime import datetime


class AG(db.Model):
Expand Down Expand Up @@ -35,10 +36,35 @@ class AG(db.Model):

events = db.relationship('Event')

messages = db.relationship('AGMessage')

unread_messages = db.relationship('AGMessage',
secondary='users_ag_messages',
primaryjoin='and_(UserAGMessage.message_id == AGMessage.id, AG.id == AGMessage.ag_id, UserAGMessage.read == 0, UserAGMessage.user_id == 1)',
viewonly=True)

read_messages = db.relationship('AGMessage',
secondary=f'users_ag_messages',
primaryjoin=f'and_(UserAGMessage.message_id == AGMessage.id, AG.id == AGMessage.ag_id, UserAGMessage.read == 1, UserAGMessage.user_id == 1)',
viewonly=True)

def __repr__(self):
return f'<AG {self.name}>'


class AGMessage(db.Model):
__tablename__ = 'ag_messages'
id = db.Column(db.Integer, primary_key=True, unique=True, nullable=False)
ag_id = db.Column(db.Integer, db.ForeignKey('ags.id'))
subject = db.Column(db.String(20))
message = db.Column(db.String(1000))
created = db.Column(db.DateTime, default=datetime.now())

users = db.relationship('UserAGMessage', secondary='users', primaryjoin='and_(AGMessage.id == UserAGMessage.message_id, UserAGMessage.user_id == User.id)', viewonly=True)

def __repr__(self):
return f'<AGMessage {self.id}>'

class AGSchema(ma.Schema):
users = ma.Nested('UserSchema', many=True, exclude=('ags',))
events = ma.Nested('EventSchema', many=True, exclude=('ag',))
Expand All @@ -61,8 +87,67 @@ class AGSchemaIntern(ma.Schema):
actual_users = ma.Nested('UserSchema', many=True, exclude=('ags',))
invited_users = ma.Nested('UserSchema', many=True, exclude=('ags',))
applied_users = ma.Nested('UserSchema', many=True, exclude=('ags',))
messages = ma.Nested('AGMessageSchema', many=True)
read_messages = ma.Method('get_read_messages')
unread_messages = ma.Method('get_unread_messages')

def get_unread_messages(self, obj: AG):
if not g.session.authenticated:
return None
ag_id = obj.id
ag_message = db.session.query(AGMessage).join(UserAGMessage, and_(AGMessage.ag_id == ag_id, UserAGMessage.user_id == g.session.user_id, UserAGMessage.message_id == AGMessage.id, UserAGMessage.read == 0)).all()
ag_messages_Schema = AGMessageSchema(many=True)
return ag_messages_Schema.dump(ag_message)

def get_read_messages(self, obj: AG):
if not g.session.authenticated:
return None
print('test')
ag_id = obj.id
ag_message = db.session.query(AGMessage).join(UserAGMessage, and_(AGMessage.ag_id == ag_id, UserAGMessage.user_id == g.session.user_id, UserAGMessage.message_id == AGMessage.id, UserAGMessage.read == 1)).all()
if len(ag_message) > 1:
ag_messages_Schema = AGMessageSchema(many=True, exclude=('users',))
else:
ag_messages_Schema = AGMessageSchema(many=True, exclude=('users',))

print(ag_messages_Schema.dump(ag_message))
print('test')
return ag_messages_Schema.dump(ag_message)


class Meta:
fields = (
'id', 'name', 'display_name', 'description', 'users', 'events', 'color', 'actual_users', 'invited_users',
'applied_users')
'applied_users', 'messages', 'unread_messages', 'read_messages')




class AGMessageSchema(ma.Schema):
read = ma.Method('get_read_status')
users = ma.Nested('UserAGMessageSchema', many=True)


def get_read_status(self, obj: AGMessage):
if not g.session.authenticated:
return None
user_ag_message = db.session.query(UserAGMessage).filter_by(user_id = g.session.user_id, message_id=obj.id).scalar()
return user_ag_message.read


class Meta:
fields = (
'id', 'ag_id', 'subject', 'message', 'read', 'created', 'users'
)

class Message(db.Model):
__tablename__ = 'messages'
id = db.Column(db.Integer, primary_key=True, unique=True, nullable=False)
subject = db.Column(db.String(20))
message = db.Column(db.String(1000))
created = db.Column(db.DateTime, default=datetime.now())


def __repr__(self):
return f'<Message {self.id}>'

21 changes: 21 additions & 0 deletions app/models/associations.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from app import ma
from app.models import db
from datetime import datetime


class UserAG(db.Model):
Expand Down Expand Up @@ -37,3 +39,22 @@ class UserDate(db.Model):

def __repr__(self):
return f'<UserDate {self.id}>'

class UserAGMessage(db.Model):
__tablename__ = 'users_ag_messages'
id = db.Column(db.Integer, primary_key=True, unique=True, nullable=False)

user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
message_id = db.Column(db.Integer, db.ForeignKey('ag_messages.id'))
read = db.Column(db.Boolean, default=False)
updated = db.Column(db.DateTime, onupdate=datetime.now())
user = db.relationship('User')


def __repr__(self):
return f'<UserAGMessage {self.id}>'

class UserAGMessageSchema(ma.Schema):
user = ma.Nested('UserSchema')
class Meta:
fields = ('user_id', 'read', 'updated', 'user')
2 changes: 2 additions & 0 deletions app/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class User(db.Model):
dates = db.relationship('Date', secondary='users_dates')
sessions = db.relationship('Session')

unread_messages = db.relationship('UserAGMessage', primaryjoin='and_(User.id == UserAGMessage.user_id, UserAGMessage.read == 0)', viewonly=True)

def __init__(self):
self.confirmation_token = secrets.token_hex(32)

Expand Down
Loading