57b54baabe
Reworking NewProject as a standalone and making NewProjectWithUser for use with signup style tasks. NewProject and NewProjectWithUser now create the project and user at post_approve and then resets the user password at submit. - This change allows signup tokens to expire and a new signup to use the reset feature to still get access. The process still appears exactly the same to the end user. - Existing users creating a new project will also get created at post_approve step, but as they needed no token this functionality does not change from an outside perspective. Fixing a project creation issue with keystone V3, wasn't setting domain. More standardisation in action handling functions. Duplicate error now returns 409 rather than 400 for clarity. Adding an "approved_by" values to tasks both for auditing and for possible future logic checks. Reworking of Network resource creation into two variant actions. Reworking AddAdminToProject to be more generic and allow a list of users. Fixing issues with logic for task approval and task updating. Change-Id: Ieba9907e5632dd441a86c41de291c6a7d0c8764a
161 lines
4.9 KiB
Python
161 lines
4.9 KiB
Python
# Copyright (C) 2015 Catalyst IT Ltd
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from django.db import models
|
|
from uuid import uuid4
|
|
from django.utils import timezone
|
|
from jsonfield import JSONField
|
|
|
|
|
|
def hex_uuid():
|
|
return uuid4().hex
|
|
|
|
|
|
class Task(models.Model):
|
|
"""
|
|
Wrapper object for the request and related actions.
|
|
Stores the state of the Task and a log for the
|
|
action.
|
|
"""
|
|
uuid = models.CharField(max_length=32, default=hex_uuid,
|
|
primary_key=True)
|
|
hash_key = models.CharField(max_length=64, db_index=True)
|
|
|
|
# who is this:
|
|
ip_address = models.GenericIPAddressField()
|
|
keystone_user = JSONField(default={})
|
|
project_id = models.CharField(max_length=32, db_index=True, null=True)
|
|
|
|
# keystone_user for the approver:
|
|
approved_by = JSONField(default={})
|
|
|
|
# type of the task, for easy grouping
|
|
task_type = models.CharField(max_length=100, db_index=True)
|
|
|
|
# Effectively a log of what the actions are doing.
|
|
action_notes = JSONField(default={})
|
|
|
|
cancelled = models.BooleanField(default=False, db_index=True)
|
|
approved = models.BooleanField(default=False, db_index=True)
|
|
completed = models.BooleanField(default=False, db_index=True)
|
|
|
|
created_on = models.DateTimeField(default=timezone.now)
|
|
approved_on = models.DateTimeField(null=True)
|
|
completed_on = models.DateTimeField(null=True)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(Task, self).__init__(*args, **kwargs)
|
|
# in memory dict to be used for passing data between actions:
|
|
self.cache = {}
|
|
|
|
@property
|
|
def actions(self):
|
|
return self.action_set.order_by('order')
|
|
|
|
@property
|
|
def tokens(self):
|
|
return self.token_set.all()
|
|
|
|
@property
|
|
def notifications(self):
|
|
return self.notification_set.all()
|
|
|
|
def _to_dict(self):
|
|
actions = []
|
|
for action in self.actions:
|
|
actions.append({
|
|
"action_name": action.action_name,
|
|
"data": action.action_data,
|
|
"valid": action.valid
|
|
})
|
|
|
|
return {
|
|
"uuid": self.uuid,
|
|
"ip_address": self.ip_address,
|
|
"keystone_user": self.keystone_user,
|
|
"approved_by": self.approved_by,
|
|
"project_id": self.project_id,
|
|
"actions": actions,
|
|
"task_type": self.task_type,
|
|
"action_notes": self.action_notes,
|
|
"cancelled": self.cancelled,
|
|
"approved": self.approved,
|
|
"completed": self.completed,
|
|
"created_on": self.created_on,
|
|
"approved_on": self.approved_on,
|
|
"completed_on": self.completed_on,
|
|
}
|
|
|
|
def to_dict(self):
|
|
"""
|
|
Slightly safer variant of the above for non-admin.
|
|
"""
|
|
task_dict = self._to_dict()
|
|
task_dict.pop("ip_address")
|
|
return task_dict
|
|
|
|
def add_action_note(self, action, note):
|
|
if action in self.action_notes:
|
|
self.action_notes[action].append(note)
|
|
else:
|
|
self.action_notes[action] = [note]
|
|
self.save()
|
|
|
|
|
|
class Token(models.Model):
|
|
"""
|
|
UUID token object bound to a task.
|
|
"""
|
|
|
|
task = models.ForeignKey(Task)
|
|
token = models.CharField(max_length=32, primary_key=True)
|
|
created_on = models.DateTimeField(default=timezone.now)
|
|
expires = models.DateTimeField(db_index=True)
|
|
|
|
def to_dict(self):
|
|
return {
|
|
"task": self.task.uuid,
|
|
"token": self.token,
|
|
"created_on": self.created_on,
|
|
"expires": self.expires
|
|
}
|
|
|
|
@property
|
|
def expired(self):
|
|
return self.expires < timezone.now()
|
|
|
|
|
|
class Notification(models.Model):
|
|
"""
|
|
Notification linked to a task with some notes.
|
|
"""
|
|
|
|
uuid = models.CharField(max_length=32, default=hex_uuid,
|
|
primary_key=True)
|
|
notes = JSONField(default={})
|
|
task = models.ForeignKey(Task)
|
|
error = models.BooleanField(default=False, db_index=True)
|
|
created_on = models.DateTimeField(default=timezone.now)
|
|
acknowledged = models.BooleanField(default=False, db_index=True)
|
|
|
|
def to_dict(self):
|
|
return {
|
|
"uuid": self.uuid,
|
|
"notes": self.notes,
|
|
"task": self.task.uuid,
|
|
"error": self.error,
|
|
"acknowledged": self.acknowledged,
|
|
"created_on": self.created_on
|
|
}
|