diff --git a/decorators.py b/decorators.py index cdc3e19b081b302bbdc1035c9324651154b36ab4..30fd142c8eedfdef29b4da748073397176a4ca32 100644 --- a/decorators.py +++ b/decorators.py @@ -73,5 +73,8 @@ def require_private_view_right(require_exist=True): def require_modify_right(require_exist=True): return require_right("modify", require_exist) +def require_publish_right(require_exist=True): + return require_right("publish", require_exist) + def require_admin_right(require_exist=True): return require_right("admin", require_exist) diff --git a/migrations/versions/279bfa293885_.py b/migrations/versions/279bfa293885_.py new file mode 100644 index 0000000000000000000000000000000000000000..c6c6dd8cff93c07e280cb5174885d9d1cd1671a5 --- /dev/null +++ b/migrations/versions/279bfa293885_.py @@ -0,0 +1,46 @@ +"""empty message + +Revision ID: 279bfa293885 +Revises: 0686095ee9dd +Create Date: 2017-05-06 21:28:13.577142 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker + +Session = sessionmaker() + +Base = declarative_base() + +class ProtocolType(Base): + __tablename__ = "protocoltypes" + id = sa.Column(sa.Integer, primary_key=True) + modify_group = sa.Column(sa.String) + publish_group = sa.Column(sa.String) + + +# revision identifiers, used by Alembic. +revision = '279bfa293885' +down_revision = '0686095ee9dd' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('protocoltypes', sa.Column('publish_group', sa.String(), nullable=True)) + # ### end Alembic commands ### + + bind = op.get_bind() + session = Session(bind=bind) + for protocoltype in session.query(ProtocolType): + protocoltype.publish_group = protocoltype.modify_group + session.commit() + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('protocoltypes', 'publish_group') + # ### end Alembic commands ### diff --git a/models/database.py b/models/database.py index 967f0531c8a85cca11ac3bdd4e572984ed7ba5c6..a60440ccfc83cb894baf2134a11ff0071f7ae3cb 100644 --- a/models/database.py +++ b/models/database.py @@ -31,6 +31,9 @@ class DatabaseModel(db.Model): def has_modify_right(self, user): return self.get_parent().has_modify_right(user) + def has_publish_right(self, user): + return self.get_parent().has_publish_right(user) + def has_admin_right(self, user): return self.get_parent().has_admin_right(user) @@ -56,6 +59,7 @@ class ProtocolType(DatabaseModel): modify_group = db.Column(db.String) private_group = db.Column(db.String) public_group = db.Column(db.String) + publish_group = db.Column(db.String) private_mail = db.Column(db.String) public_mail = db.Column(db.String) non_reproducible_pad_links = db.Column(db.Boolean) @@ -104,6 +108,11 @@ class ProtocolType(DatabaseModel): and (self.modify_group != "" and self.modify_group in user.groups)) or self.has_admin_right(user)) + def has_publish_right(self, user): + return ((user is not None + and (self.publish_group != "" and self.publish_group in user.groups)) + or self.has_admin_right(user)) + def has_admin_right(self, user): return (user is not None and config.ADMIN_GROUP in user.groups) diff --git a/server.py b/server.py index f8181d2233b8ea1d902068b066a25cd2e4596d66..2adc7ae25261bb566cdb5f20cf308e6fb2512979 100755 --- a/server.py +++ b/server.py @@ -22,7 +22,7 @@ import mimetypes import config from shared import db, date_filter, datetime_filter, date_filter_long, date_filter_short, time_filter, time_filter_short, user_manager, security_manager, current_user, check_login, login_required, group_required, class_filter, needs_date_test, todostate_name_filter, code_filter, indent_tab_filter from utils import is_past, mail_manager, url_manager, get_first_unused_int, set_etherpad_text, get_etherpad_text, split_terms, optional_int_arg, fancy_join -from decorators import db_lookup, require_public_view_right, require_private_view_right, require_modify_right, require_admin_right +from decorators import db_lookup, require_public_view_right, require_private_view_right, require_modify_right, require_publish_right, require_admin_right from models.database import ProtocolType, Protocol, DefaultTOP, TOP, LocalTOP, Document, Todo, Decision, MeetingReminder, Error, TodoMail, DecisionDocument, TodoState, Meta, DefaultMeta, DecisionCategory, Like from views.forms import LoginForm, ProtocolTypeForm, DefaultTopForm, MeetingReminderForm, NewProtocolForm, DocumentUploadForm, KnownProtocolSourceUploadForm, NewProtocolSourceUploadForm, generate_protocol_form, TopForm, LocalTopForm, SearchForm, DecisionSearchForm, ProtocolSearchForm, TodoSearchForm, NewProtocolFileUploadForm, NewTodoForm, TodoForm, TodoMailForm, DefaultMetaForm, MetaForm, MergeTodosForm, DecisionCategoryForm, DocumentEditForm from views.tables import ProtocolsTable, ProtocolTypesTable, ProtocolTypeTable, DefaultTOPsTable, MeetingRemindersTable, ErrorsTable, TodosTable, DocumentsTable, DecisionsTable, TodoTable, ErrorTable, TodoMailsTable, DefaultMetasTable, DecisionCategoriesTable @@ -688,7 +688,7 @@ def etherpush_protocol(protocol): @app.route("/protocol/update/<int:protocol_id>", methods=["GET", "POST"]) @login_required @db_lookup(Protocol) -@require_modify_right() +@require_publish_right() def update_protocol(protocol): upload_form = KnownProtocolSourceUploadForm() edit_form = generate_protocol_form(protocol)(obj=protocol) @@ -706,7 +706,7 @@ def update_protocol(protocol): @app.route("/protocol/publish/<int:protocol_id>") @login_required @db_lookup(Protocol) -@require_modify_right() +@require_publish_right() def publish_protocol(protocol): protocol.public = True db.session.commit() @@ -727,7 +727,7 @@ def send_protocol_private(protocol): @app.route("/prococol/send/public/<int:protocol_id>") @login_required @db_lookup(Protocol) -@require_modify_right() +@require_publish_right() def send_protocol_public(protocol): if not config.MAIL_ACTIVE: flash("Die Mailfunktion ist nicht aktiviert.", "alert-error") diff --git a/views/forms.py b/views/forms.py index 0fd10eef0cdd75fec210d525ae39f2c4ac27754a..7d42f07a642ffed0bdd56bee803f01a0317b535d 100644 --- a/views/forms.py +++ b/views/forms.py @@ -109,6 +109,7 @@ class ProtocolTypeForm(FlaskForm): organization = StringField("Organisation", validators=[InputRequired("Du musst eine zugehörige Organisation angeben.")]) usual_time = DateTimeField("Üblicher Beginn", validators=[InputRequired("Bitte gib die Zeit an, zu der die Sitzung beginnt.")], format="%H:%M") is_public = BooleanField("Öffentlich sichtbar") + publish_group = SelectField("Verwaltungsgruppe", choices=[]) modify_group = SelectField("Bearbeitungsgruppe", choices=[]) private_group = SelectField("Interne Gruppe", choices=[]) public_group = SelectField("Öffentliche Gruppe", choices=[]) @@ -129,6 +130,7 @@ class ProtocolTypeForm(FlaskForm): self.calendar.choices = get_calendar_choices(protocoltype=protocoltype) self.printer.choices = get_printer_choices() group_choices = get_group_choices() + self.publish_group.choices = group_choices self.modify_group.choices = group_choices self.private_group.choices = group_choices self.public_group.choices = group_choices diff --git a/views/tables.py b/views/tables.py index 9f3054dd7573e472972c14a4afda21cd0c40a7c0..75592bfa8f4c6f635ab46be5dd5d1c55a5547cba 100644 --- a/views/tables.py +++ b/views/tables.py @@ -159,7 +159,7 @@ class ProtocolTypeTable(SingleValueTable): def headers(self): general_headers = ["Name", "Abkürzung", "Organisation", "Beginn", - "Öffentlich", "Bearbeitungsgruppe", "Interne Gruppe", + "Öffentlich", "Verwaltungsgruppe", "Bearbeitungsgruppe", "Interne Gruppe", "Öffentliche Gruppe"] etherpad_headers = ["Nicht-reproduzierbare Etherpadlinks"] if not config.ETHERPAD_ACTIVE: @@ -190,6 +190,7 @@ class ProtocolTypeTable(SingleValueTable): self.value.organization, self.value.usual_time.strftime("%H:%M") if self.value.usual_time is not None else "", # todo: remove if, this field is required Table.bool(self.value.is_public), + self.value.publish_group, self.value.modify_group, self.value.private_group, self.value.public_group,