Skip to content

Commit

Permalink
bug 1310188: Enable Scheduled Changes for Releases and Permissions (#196
Browse files Browse the repository at this point in the history
). r=nthomas
  • Loading branch information
bhearsum committed Jan 12, 2017
1 parent cf4c57a commit c6b8b91
Show file tree
Hide file tree
Showing 15 changed files with 1,298 additions and 94 deletions.
24 changes: 22 additions & 2 deletions auslib/admin/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@

from auslib.admin.views.csrf import CSRFView
from auslib.admin.views.permissions import UsersView, PermissionsView, \
SpecificPermissionView, UserRolesView, UserRoleView
SpecificPermissionView, UserRolesView, UserRoleView, \
PermissionScheduledChangesView, PermissionScheduledChangeView, \
EnactPermissionScheduledChangeView, PermissionScheduledChangeHistoryView, \
PermissionScheduledChangeSignoffsView
from auslib.admin.views.releases import SingleLocaleView, \
SingleReleaseView, ReleaseHistoryView, \
ReleasesAPIView, SingleReleaseColumnView, ReleaseReadOnlyView
ReleasesAPIView, SingleReleaseColumnView, ReleaseReadOnlyView, \
ReleaseScheduledChangesView, ReleaseScheduledChangeView, \
EnactReleaseScheduledChangeView, ReleaseScheduledChangeHistoryView, \
ReleaseScheduledChangeSignoffsView
from auslib.admin.views.rules import RulesAPIView, \
SingleRuleView, RuleHistoryAPIView, SingleRuleColumnView, \
RuleScheduledChangesView, RuleScheduledChangeView, \
Expand Down Expand Up @@ -59,6 +65,7 @@ def add_security_headers(response):
response.headers['X-Content-Type-Options'] = 'nosniff'
return response


Compress(app)


Expand Down Expand Up @@ -92,3 +99,16 @@ def add_security_headers(response):
app.add_url_rule("/scheduled_changes/rules/<int:sc_id>/enact", view_func=EnactRuleScheduledChangeView.as_view("enact_scheduled_change_rules"))
app.add_url_rule("/scheduled_changes/rules/<int:sc_id>/signoffs", view_func=RuleScheduledChangeSignoffsView.as_view("scheduled_change_rules_signoffs"))
app.add_url_rule("/scheduled_changes/rules/<int:sc_id>/revisions", view_func=RuleScheduledChangeHistoryView.as_view("scheduled_change_rules_history"))
app.add_url_rule("/scheduled_changes/permissions", view_func=PermissionScheduledChangesView.as_view("scheduled_changes_permissions"))
app.add_url_rule("/scheduled_changes/permissions/<int:sc_id>", view_func=PermissionScheduledChangeView.as_view("scheduled_change_permissions"))
app.add_url_rule("/scheduled_changes/permissions/<int:sc_id>/enact", view_func=EnactPermissionScheduledChangeView.as_view("enact_scheduled_change_permissions"))
app.add_url_rule("/scheduled_changes/permissions/<int:sc_id>/signoffs",
view_func=PermissionScheduledChangeSignoffsView.as_view("scheduled_change_permissions_signoffs"))
app.add_url_rule("/scheduled_changes/permissions/<int:sc_id>/revisions",
view_func=PermissionScheduledChangeHistoryView.as_view("scheduled_change_permissions_history"))
app.add_url_rule("/scheduled_changes/releases", view_func=ReleaseScheduledChangesView.as_view("scheduled_changes_releases"))
app.add_url_rule("/scheduled_changes/releases/<int:sc_id>", view_func=ReleaseScheduledChangeView.as_view("scheduled_change_releases"))
app.add_url_rule("/scheduled_changes/releases/<int:sc_id>/enact", view_func=EnactReleaseScheduledChangeView.as_view("enact_scheduled_change_releases"))
app.add_url_rule("/scheduled_changes/releases/<int:sc_id>/signoffs", view_func=ReleaseScheduledChangeSignoffsView.as_view("scheduled_change_release_signoffs"))
app.add_url_rule("/scheduled_changes/releases/<int:sc_id>/revisions",
view_func=ReleaseScheduledChangeHistoryView.as_view("scheduled_change_releases_history"))
121 changes: 110 additions & 11 deletions auslib/admin/views/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,14 @@ class DbEditableForm(Form):
data_version = IntegerField('data_version', validators=[InputRequired()], widget=HiddenInput())


class ScheduledChangeForm(Form):
class ScheduledChangeTimeForm(Form):
when = IntegerField("When", validators=[Optional(), not_in_the_past()])


class ScheduledChangeUptakeForm(Form):
telemetry_product = NullableStringField("Telemetry Product")
telemetry_channel = NullableStringField("Telemetry Channel")
telemetry_uptake = NullableStringField("Telemetry Uptake")
when = IntegerField("When", validators=[Optional(), not_in_the_past()])


class NewPermissionForm(Form):
Expand All @@ -155,6 +158,54 @@ class ExistingPermissionForm(DbEditableForm):
options = JSONStringField(None, 'Options')


class ScheduledChangeNewPermissionForm(ScheduledChangeTimeForm):
"""Permission and username are required when creating a new Permission, so they
must be provided when Scheduled a Change that does the same. Options may also be
provided."""
permission = StringField('Permission', validators=[Length(0, 50), InputRequired()])
username = StringField('Username', validators=[Length(0, 100), InputRequired()])
options = JSONStringField(None, 'Options')
change_type = SelectField("Change Type", choices=[('insert', 'insert'), ('update', 'update'), ('delete'), ('delete')])


class ScheduledChangeExistingPermissionForm(ScheduledChangeTimeForm):
"""Permissions and username are required when Scheduling a Change that changes
an existing Permission because they are needed to find that Permission. Options
may also be provided."""
permission = StringField('Permission', validators=[Length(0, 50), InputRequired()])
username = StringField('Username', validators=[Length(0, 100), InputRequired()])
options = JSONStringField(None, 'Options')
data_version = IntegerField('data_version', validators=[InputRequired()], widget=HiddenInput())
change_type = SelectField("Change Type", choices=[('insert', 'insert'), ('update', 'update'), ('delete'), ('delete')])


class ScheduledChangeDeletePermissionForm(ScheduledChangeTimeForm):
"""Permissions and username are required when Scheduling a Change that deletes
an existing Permission because they are needed to find that Permission."""
permission = StringField('Permission', validators=[Length(0, 50), InputRequired()])
username = StringField('Username', validators=[Length(0, 100), InputRequired()])
data_version = IntegerField('data_version', validators=[InputRequired()], widget=HiddenInput())
change_type = SelectField("Change Type", choices=[('insert', 'insert'), ('update', 'update'), ('delete', 'delete')])


class EditScheduledChangeNewPermissionForm(ScheduledChangeTimeForm):
"""When editing an existing Scheduled Change for a Permission, any field
may be changed."""
permission = StringField('Permission', validators=[Length(0, 50), Optional()])
username = StringField('Username', validators=[Length(0, 100), Optional()])
options = JSONStringField(None, 'Options')
sc_data_version = IntegerField('sc_data_version', validators=[InputRequired()], widget=HiddenInput())


class EditScheduledChangeExistingPermissionForm(ScheduledChangeTimeForm):
"""When editing an existing Scheduled Change for a Permission only options may be
provided. Because edits are identified by sc_id (in the URL), permission and username
are not required (nor allowed, because they are PK fields)."""
options = JSONStringField(None, 'Options')
data_version = IntegerField('data_version', widget=HiddenInput())
sc_data_version = IntegerField('sc_data_version', validators=[InputRequired()], widget=HiddenInput())


class PartialReleaseForm(Form):
# Because we do implicit release creation in the Releases views, we can't
# have data_version be InputRequired(). The views are responsible for checking
Expand Down Expand Up @@ -212,40 +263,40 @@ class EditRuleForm(DbEditableForm):
headerArchitecture = NullableStringField('Header Architecture', validators=[Optional(), Length(0, 10)])


class ScheduledChangeNewRuleForm(ScheduledChangeForm, RuleForm):
class ScheduledChangeNewRuleForm(ScheduledChangeTimeForm, ScheduledChangeUptakeForm, RuleForm):
change_type = SelectField("Change Type", choices=[('insert', 'insert'), ('update', 'update'), ('delete'), ('delete')])


class ScheduledChangeExistingRuleForm(ScheduledChangeForm, EditRuleForm):
class ScheduledChangeExistingRuleForm(ScheduledChangeTimeForm, ScheduledChangeUptakeForm, EditRuleForm):
# EditRuleForm doesn't have rule_id in it because rules are edited through
# URLs that contain them. Scheduled changes, on the other hand, are edited
# through URLs that contain scheduled change IDs, so we need to include
# the rule_id in the form when editing scheduled changes for rules.
change_type = SelectField("Change Type", choices=[('insert', 'insert'), ('update', 'update'), ('delete'), ('delete')])
rule_id = IntegerField('Rule ID', validators=[InputRequired()])
change_type = SelectField("Change Type", choices=[('insert', 'insert'), ('update', 'update'), ('delete'), ('delete')])


class ScheduledChangeDeleteRuleForm(ScheduledChangeForm):
class ScheduledChangeDeleteRuleForm(ScheduledChangeTimeForm, ScheduledChangeUptakeForm):
"""
ScheduledChangeDeletionForm includes all the PK columns ,ScheduledChangeForm columns and data version
"""
change_type = SelectField("Change Type", choices=[('insert', 'insert'), ('update', 'update'), ('delete', 'delete')])
rule_id = IntegerField('Rule ID', validators=[InputRequired()])
data_version = IntegerField('data_version', widget=HiddenInput())
data_version = IntegerField('data_version', validators=[InputRequired()], widget=HiddenInput())
change_type = SelectField("Change Type", choices=[('insert', 'insert'), ('update', 'update'), ('delete', 'delete')])


class EditScheduledChangeNewRuleForm(ScheduledChangeForm, RuleForm):
class EditScheduledChangeNewRuleForm(ScheduledChangeTimeForm, ScheduledChangeUptakeForm, RuleForm):
sc_data_version = IntegerField('sc_data_version', validators=[InputRequired()], widget=HiddenInput())


# Unlike when scheduling a new change to an existing rule, rule_id is not
# required (or even allowed) when modifying a scheduled change for an
# existing rule. Allowing it to be modified would be confusing.
class EditScheduledChangeExistingRuleForm(ScheduledChangeForm, EditRuleForm):
class EditScheduledChangeExistingRuleForm(ScheduledChangeTimeForm, ScheduledChangeUptakeForm, EditRuleForm):
sc_data_version = IntegerField('sc_data_version', validators=[InputRequired()], widget=HiddenInput())


class EditScheduledChangeDeleteRuleForm(ScheduledChangeForm):
class EditScheduledChangeDeleteRuleForm(ScheduledChangeTimeForm, ScheduledChangeUptakeForm):
sc_data_version = IntegerField('sc_data_version', validators=[InputRequired()], widget=HiddenInput())


Expand All @@ -265,3 +316,51 @@ class ReadOnlyForm(Form):
product = StringField('Product', validators=[InputRequired()])
read_only = BooleanField('read_only')
data_version = IntegerField('data_version', widget=HiddenInput())


class ScheduledChangeNewReleaseForm(ScheduledChangeTimeForm):
"""All Release fields (name, product, data) are required when creating
a new Release, so they must be provided when Scheduling a Change that
does the same."""
name = StringField('Name', validators=[InputRequired()])
product = StringField('Product', validators=[InputRequired()])
data = JSONStringField({}, 'Data', validators=[InputRequired()], widget=FileInput())
change_type = SelectField("Change Type", choices=[('insert', 'insert'), ('update', 'update'), ('delete'), ('delete')])


class ScheduledChangeExistingReleaseForm(ScheduledChangeTimeForm):
"""Name must be provided when Scheduling a Change that modifies an existing
Release so that we can identify it. Other Release fields (product, data) are
optional."""
name = StringField('Name', validators=[InputRequired()])
product = StringField('Product', validators=[Optional()])
data = JSONStringField({}, 'Data', validators=[Optional()], widget=FileInput())
data_version = IntegerField('data_version', validators=[InputRequired()], widget=HiddenInput())
change_type = SelectField("Change Type", choices=[('insert', 'insert'), ('update', 'update'), ('delete'), ('delete')])


class ScheduledChangeDeleteReleaseForm(ScheduledChangeTimeForm):
"""Name must be provided when Scheduling a Change that deletes an
existing Permission so that we can find it."""
name = StringField('Name', validators=[InputRequired()])
data_version = IntegerField('data_version', validators=[InputRequired()], widget=HiddenInput())
change_type = SelectField("Change Type", choices=[('insert', 'insert'), ('update', 'update'), ('delete', 'delete')])


class EditScheduledChangeNewReleaseForm(ScheduledChangeTimeForm):
"""Any Release field may be changed when editing an Scheduled Change for a new
Release."""
name = StringField('Name', validators=[Optional()])
product = StringField('Product', validators=[Optional()])
data = JSONStringField({}, 'Data', validators=[Optional()], widget=FileInput())
sc_data_version = IntegerField('sc_data_version', validators=[InputRequired()], widget=HiddenInput())


class EditScheduledChangeExistingReleaseForm(ScheduledChangeTimeForm):
"""Only data may be changed when editing an existing Scheduled Change for
a Release. Name cannot be changed because it is a PK field, and product
cannot be changed because it almost never makes sense to (and can be done
by deleting/recreating instead)."""
data = JSONStringField({}, 'Data', validators=[Optional()], widget=FileInput())
data_version = IntegerField('data_version', widget=HiddenInput())
sc_data_version = IntegerField('sc_data_version', validators=[InputRequired()], widget=HiddenInput())
77 changes: 76 additions & 1 deletion auslib/admin/views/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@

from auslib.global_state import dbo
from auslib.admin.views.base import requirelogin, AdminView
from auslib.admin.views.forms import NewPermissionForm, ExistingPermissionForm, DbEditableForm
from auslib.admin.views.forms import NewPermissionForm, ExistingPermissionForm, DbEditableForm, \
ScheduledChangeNewPermissionForm, ScheduledChangeExistingPermissionForm, \
EditScheduledChangeNewPermissionForm, EditScheduledChangeExistingPermissionForm, \
ScheduledChangeDeletePermissionForm
from auslib.admin.views.scheduled_changes import ScheduledChangesView, \
ScheduledChangeView, EnactScheduledChangeView, ScheduledChangeHistoryView, \
SignoffsView

__all__ = ["UsersView", "PermissionsView", "SpecificPermissionView"]

Expand Down Expand Up @@ -97,6 +103,75 @@ def _delete(self, username, permission, changed_by, transaction):
return Response(status=400, response=e.args)


class PermissionScheduledChangesView(ScheduledChangesView):
def __init__(self):
super(PermissionScheduledChangesView, self).__init__("permissions", dbo.permissions)

@requirelogin
def _post(self, transaction, changed_by):
change_type = request.json.get("change_type")

if change_type == "update":
form = ScheduledChangeExistingPermissionForm()
elif change_type == "insert":
form = ScheduledChangeNewPermissionForm()
elif change_type == "delete":
form = ScheduledChangeDeletePermissionForm()
else:
return Response(status=400, response="Invalid or missing change_type")

return super(PermissionScheduledChangesView, self)._post(form, transaction, changed_by)


class PermissionScheduledChangeView(ScheduledChangeView):
def __init__(self):
super(PermissionScheduledChangeView, self).__init__("permissions", dbo.permissions)

@requirelogin
def _post(self, sc_id, transaction, changed_by):
if request.json and request.json.get("data_version"):
form = EditScheduledChangeExistingPermissionForm()
else:
form = EditScheduledChangeNewPermissionForm()

return super(PermissionScheduledChangeView, self)._post(sc_id, form, transaction, changed_by)

@requirelogin
def _delete(self, sc_id, transaction, changed_by):
return super(PermissionScheduledChangeView, self)._delete(sc_id, transaction, changed_by)


class EnactPermissionScheduledChangeView(EnactScheduledChangeView):
def __init__(self):
super(EnactPermissionScheduledChangeView, self).__init__("permissions", dbo.permissions)

@requirelogin
def _post(self, sc_id, transaction, changed_by):
return super(EnactPermissionScheduledChangeView, self)._post(sc_id, transaction, changed_by)


class PermissionScheduledChangeSignoffsView(SignoffsView):
def __init__(self):
super(PermissionScheduledChangeSignoffsView, self).__init__("permissions", dbo.permissions)

@requirelogin
def _post(self, sc_id, transaction, changed_by):
return super(PermissionScheduledChangeSignoffsView, self)._post(sc_id, transaction, changed_by)

@requirelogin
def _delete(self, sc_id, transaction, changed_by):
return super(PermissionScheduledChangeSignoffsView, self)._delete(sc_id, transaction, changed_by)


class PermissionScheduledChangeHistoryView(ScheduledChangeHistoryView):
def __init__(self):
super(PermissionScheduledChangeHistoryView, self).__init__("permissions", dbo.permissions)

@requirelogin
def _post(self, sc_id, transaction, changed_by):
return super(PermissionScheduledChangeHistoryView, self)._post(sc_id, transaction, changed_by)


class UserRolesView(AdminView):
"""/users/:username/roles"""

Expand Down

0 comments on commit c6b8b91

Please sign in to comment.