1 # -*- coding: utf-8 -*-
5 from hashlib
import sha256
6 from http
import HTTPStatus
7 from validation
import user_new_schema
, user_edit_schema
, project_new_schema
, project_edit_schema
8 from validation
import vim_account_new_schema
, vim_account_edit_schema
, sdn_new_schema
, sdn_edit_schema
9 from base_topic
import BaseTopic
, EngineException
11 __author__
= "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
14 class UserTopic(BaseTopic
):
17 schema_new
= user_new_schema
18 schema_edit
= user_edit_schema
20 def __init__(self
, db
, fs
, msg
):
21 BaseTopic
.__init
__(self
, db
, fs
, msg
)
24 def _get_project_filter(session
, write
=False, show_all
=True):
26 Generates a filter dictionary for querying database users.
27 Current policy is admin can show all, non admin, only its own user.
28 :param session: contains "username", if user is "admin" and the working "project_id"
29 :param write: if operation is for reading (False) or writing (True)
30 :param show_all: if True it will show public or
33 if session
["admin"]: # allows all
36 return {"username": session
["username"]}
38 def check_conflict_on_new(self
, session
, indata
, force
=False):
39 # check username not exists
40 if self
.db
.get_one(self
.topic
, {"username": indata
.get("username")}, fail_on_empty
=False, fail_on_more
=False):
41 raise EngineException("username '{}' exists".format(indata
["username"]), HTTPStatus
.CONFLICT
)
44 for p
in indata
["projects"]:
47 if not self
.db
.get_one("projects", {"_id": p
}, fail_on_empty
=False, fail_on_more
=False):
48 raise EngineException("project '{}' does not exists".format(p
), HTTPStatus
.CONFLICT
)
50 def check_conflict_on_del(self
, session
, _id
, force
=False):
51 if _id
== session
["username"]:
52 raise EngineException("You cannot delete your own user", http_code
=HTTPStatus
.CONFLICT
)
55 def format_on_new(content
, project_id
=None, make_public
=False):
56 BaseTopic
.format_on_new(content
, make_public
=False)
57 content
["_id"] = content
["username"]
59 content
["_admin"]["salt"] = salt
60 if content
.get("password"):
61 content
["password"] = sha256(content
["password"].encode('utf-8') + salt
.encode('utf-8')).hexdigest()
64 def format_on_edit(final_content
, edit_content
):
65 BaseTopic
.format_on_edit(final_content
, edit_content
)
66 if edit_content
.get("password"):
68 final_content
["_admin"]["salt"] = salt
69 final_content
["password"] = sha256(edit_content
["password"].encode('utf-8') +
70 salt
.encode('utf-8')).hexdigest()
72 def edit(self
, session
, _id
, indata
=None, kwargs
=None, force
=False, content
=None):
73 if not session
["admin"]:
74 raise EngineException("needed admin privileges", http_code
=HTTPStatus
.UNAUTHORIZED
)
75 return BaseTopic
.edit(self
, session
, _id
, indata
=indata
, kwargs
=kwargs
, force
=force
, content
=content
)
77 def new(self
, rollback
, session
, indata
=None, kwargs
=None, headers
=None, force
=False, make_public
=False):
78 if not session
["admin"]:
79 raise EngineException("needed admin privileges", http_code
=HTTPStatus
.UNAUTHORIZED
)
80 return BaseTopic
.new(self
, rollback
, session
, indata
=indata
, kwargs
=kwargs
, headers
=headers
, force
=force
,
81 make_public
=make_public
)
84 class ProjectTopic(BaseTopic
):
86 topic_msg
= "projects"
87 schema_new
= project_new_schema
88 schema_edit
= project_edit_schema
90 def __init__(self
, db
, fs
, msg
):
91 BaseTopic
.__init
__(self
, db
, fs
, msg
)
93 def check_conflict_on_new(self
, session
, indata
, force
=False):
94 if not indata
.get("name"):
95 raise EngineException("missing 'name'")
96 # check name not exists
97 if self
.db
.get_one(self
.topic
, {"name": indata
.get("name")}, fail_on_empty
=False, fail_on_more
=False):
98 raise EngineException("name '{}' exists".format(indata
["name"]), HTTPStatus
.CONFLICT
)
101 def format_on_new(content
, project_id
=None, make_public
=False):
102 BaseTopic
.format_on_new(content
, None)
103 content
["_id"] = content
["name"]
105 def check_conflict_on_del(self
, session
, _id
, force
=False):
106 if _id
== session
["project_id"]:
107 raise EngineException("You cannot delete your own project", http_code
=HTTPStatus
.CONFLICT
)
110 _filter
= {"projects": _id
}
111 if self
.db
.get_list("users", _filter
):
112 raise EngineException("There is some USER that contains this project", http_code
=HTTPStatus
.CONFLICT
)
114 def edit(self
, session
, _id
, indata
=None, kwargs
=None, force
=False, content
=None):
115 if not session
["admin"]:
116 raise EngineException("needed admin privileges", http_code
=HTTPStatus
.UNAUTHORIZED
)
117 return BaseTopic
.edit(self
, session
, _id
, indata
=indata
, kwargs
=kwargs
, force
=force
, content
=content
)
119 def new(self
, rollback
, session
, indata
=None, kwargs
=None, headers
=None, force
=False, make_public
=False):
120 if not session
["admin"]:
121 raise EngineException("needed admin privileges", http_code
=HTTPStatus
.UNAUTHORIZED
)
122 return BaseTopic
.new(self
, rollback
, session
, indata
=indata
, kwargs
=kwargs
, headers
=headers
, force
=force
,
123 make_public
=make_public
)
126 class VimAccountTopic(BaseTopic
):
127 topic
= "vim_accounts"
128 topic_msg
= "vim_account"
129 schema_new
= vim_account_new_schema
130 schema_edit
= vim_account_edit_schema
132 def __init__(self
, db
, fs
, msg
):
133 BaseTopic
.__init
__(self
, db
, fs
, msg
)
135 def check_conflict_on_new(self
, session
, indata
, force
=False):
136 self
.check_unique_name(session
, indata
["name"], _id
=None)
138 def check_conflict_on_edit(self
, session
, final_content
, edit_content
, _id
, force
=False):
139 if edit_content
.get("name"):
140 self
.check_unique_name(session
, edit_content
["name"], _id
=_id
)
143 def format_on_new(content
, project_id
=None, make_public
=False):
144 BaseTopic
.format_on_new(content
, project_id
=project_id
, make_public
=False)
145 content
["_admin"]["operationalState"] = "PROCESSING"
147 def delete(self
, session
, _id
, force
=False, dry_run
=False):
149 Delete item by its internal _id
150 :param session: contains the used login username, working project, and admin rights
151 :param _id: server internal id
152 :param force: indicates if deletion must be forced in case of conflict
153 :param dry_run: make checking but do not delete
154 :return: dictionary with deleted item _id. It raises EngineException on error: not found, conflict, ...
156 # TODO add admin to filter, validate rights
157 if dry_run
or force
: # delete completely
158 return BaseTopic
.delete(self
, session
, _id
, force
, dry_run
)
159 else: # if not, sent to kafka
160 v
= BaseTopic
.delete(self
, session
, _id
, force
, dry_run
=True)
161 self
.db
.set_one("vim_accounts", {"_id": _id
}, {"_admin.to_delete": True}) # TODO change status
162 self
._send
_msg
("delete", {"_id": _id
})
163 return v
# TODO indicate an offline operation to return 202 ACCEPTED
166 class SdnTopic(BaseTopic
):
169 schema_new
= sdn_new_schema
170 schema_edit
= sdn_edit_schema
172 def __init__(self
, db
, fs
, msg
):
173 BaseTopic
.__init
__(self
, db
, fs
, msg
)
175 def check_conflict_on_new(self
, session
, indata
, force
=False):
176 self
.check_unique_name(session
, indata
["name"], _id
=None)
178 def check_conflict_on_edit(self
, session
, final_content
, edit_content
, _id
, force
=False):
179 if edit_content
.get("name"):
180 self
.check_unique_name(session
, edit_content
["name"], _id
=_id
)
183 def format_on_new(content
, project_id
=None, make_public
=False):
184 BaseTopic
.format_on_new(content
, project_id
=project_id
, make_public
=False)
185 content
["_admin"]["operationalState"] = "PROCESSING"
187 def delete(self
, session
, _id
, force
=False, dry_run
=False):
189 Delete item by its internal _id
190 :param session: contains the used login username, working project, and admin rights
191 :param _id: server internal id
192 :param force: indicates if deletion must be forced in case of conflict
193 :param dry_run: make checking but do not delete
194 :return: dictionary with deleted item _id. It raises EngineException on error: not found, conflict, ...
196 if dry_run
or force
: # delete completely
197 return BaseTopic
.delete(self
, session
, _id
, force
, dry_run
)
198 else: # if not sent to kafka
199 v
= BaseTopic
.delete(self
, session
, _id
, force
, dry_run
=True)
200 self
.db
.set_one("sdns", {"_id": _id
}, {"_admin.to_delete": True}) # TODO change status
201 self
._send
_msg
("delete", {"_id": _id
})
202 return v
# TODO indicate an offline operation to return 202 ACCEPTED