Package coprs :: Package views :: Package apiv3_ns :: Module apiv3_projects
[hide private]
[frames] | no frames]

Source Code for Module coprs.views.apiv3_ns.apiv3_projects

  1  import flask 
  2  from . import query_params, get_copr, pagination, Paginator, GET, POST, PUT, DELETE 
  3  from .json2form import get_form_compatible_data, get_input_dict 
  4  from coprs import db, models, forms 
  5  from coprs.views.misc import api_login_required 
  6  from coprs.views.apiv3_ns import apiv3_ns 
  7  from coprs.logic.coprs_logic import CoprsLogic, CoprChrootsLogic, MockChrootsLogic 
  8  from coprs.logic.complex_logic import ComplexLogic 
  9  from coprs.logic.users_logic import UsersLogic 
 10  from coprs.exceptions import (DuplicateException, NonAdminCannotCreatePersistentProject, 
 11                                NonAdminCannotDisableAutoPrunning, ActionInProgressException, 
 12                                InsufficientRightsException, BadRequest, ObjectNotFound) 
13 14 15 -def to_dict(copr):
16 return { 17 "id": copr.id, 18 "name": copr.name, 19 "ownername": copr.owner_name, 20 "full_name": copr.full_name, 21 "homepage": copr.homepage, 22 "contact": copr.contact, 23 "description": copr.description, 24 "instructions": copr.instructions, 25 "devel_mode": copr.devel_mode, 26 "persistent": copr.persistent, 27 "unlisted_on_hp": copr.unlisted_on_hp, 28 "auto_prune": copr.auto_prune, 29 "chroot_repos": CoprsLogic.get_yum_repos(copr, empty=True), 30 "additional_repos": copr.repos_list, 31 "enable_net": copr.build_enable_net, 32 "bootstrap": copr.bootstrap, 33 "module_hotfixes": copr.module_hotfixes, 34 }
35
36 37 -def rename_fields(input):
38 replace = { 39 "devel_mode": "disable_createrepo", 40 "additional_repos": "repos", 41 } 42 output = input.copy() 43 for from_name, to_name in replace.items(): 44 if from_name not in output: 45 continue 46 output[to_name] = output.pop(from_name) 47 return output
48
49 50 -def validate_chroots(input, allowed_chroots):
51 inserted = set(input.get("chroots") or []) 52 allowed = {x.name for x in allowed_chroots} 53 unexpected = inserted - allowed 54 if unexpected: 55 raise BadRequest("Unexpected chroot: {}".format(", ".join(unexpected)))
56
57 58 -def owner2tuple(ownername):
59 """ 60 This function takes `ownername` on its input. That can be either some 61 username or a group name starting with @ character. Then it returns a tuple 62 of two objects - `models.User` and `models.Group`. 63 64 Every project (even a group one) needs to have some user assigned to it, so 65 this value will always be some user object. Group can obviously be `None`. 66 """ 67 user = flask.g.user 68 group = None 69 if ownername[0] == "@": 70 group = ComplexLogic.get_group_by_name_safe(ownername[1:]) 71 elif ownername != flask.g.user.name: 72 user = UsersLogic.get(ownername).first() 73 if not user: 74 raise ObjectNotFound("No such user `{0}'".format(ownername)) 75 return user, group
76
77 78 @apiv3_ns.route("/project", methods=GET) 79 @query_params() 80 -def get_project(ownername, projectname):
81 copr = get_copr(ownername, projectname) 82 return flask.jsonify(to_dict(copr))
83
84 85 @apiv3_ns.route("/project/list", methods=GET) 86 @pagination() 87 @query_params() 88 -def get_project_list(ownername=None, **kwargs):
89 if not ownername: 90 query = CoprsLogic.get_multiple() 91 elif ownername.startswith("@"): 92 group_name = ownername[1:] 93 query = CoprsLogic.get_multiple() 94 query = CoprsLogic.filter_by_group_name(query, group_name) 95 else: 96 query = CoprsLogic.get_multiple_owned_by_username(ownername) 97 query = CoprsLogic.filter_without_group_projects(query) 98 99 paginator = Paginator(query, models.Copr, **kwargs) 100 projects = paginator.map(to_dict) 101 return flask.jsonify(items=projects, meta=paginator.meta)
102
103 104 @apiv3_ns.route("/project/search", methods=GET) 105 @pagination() 106 @query_params() 107 # @TODO should the param be query or projectname? 108 -def search_projects(query, **kwargs):
109 try: 110 search_query = CoprsLogic.get_multiple_fulltext(query) 111 paginator = Paginator(search_query, models.Copr, **kwargs) 112 projects = paginator.map(to_dict) 113 except ValueError as ex: 114 raise BadRequest(str(ex)) 115 return flask.jsonify(items=projects, meta=paginator.meta)
116
117 118 @apiv3_ns.route("/project/add/<ownername>", methods=POST) 119 @api_login_required 120 -def add_project(ownername):
121 user, group = owner2tuple(ownername) 122 data = rename_fields(get_form_compatible_data()) 123 form = forms.CoprFormFactory.create_form_cls(user=user, group=group)(data, meta={'csrf': False}) 124 125 if not form.validate_on_submit(): 126 raise BadRequest(form.errors) 127 validate_chroots(get_input_dict(), MockChrootsLogic.get_multiple()) 128 129 bootstrap = None 130 # backward compatibility 131 use_bootstrap_container = form.use_bootstrap_container.data 132 if use_bootstrap_container is not None: 133 bootstrap = "on" if use_bootstrap_container else "off" 134 if form.bootstrap.data is not None: 135 bootstrap = form.bootstrap.data 136 137 try: 138 copr = CoprsLogic.add( 139 name=form.name.data.strip(), 140 repos=" ".join(form.repos.data.split()), 141 user=user, 142 selected_chroots=form.selected_chroots, 143 description=form.description.data, 144 instructions=form.instructions.data, 145 check_for_duplicates=True, 146 unlisted_on_hp=form.unlisted_on_hp.data, 147 build_enable_net=form.enable_net.data, 148 group=group, 149 persistent=form.persistent.data, 150 auto_prune=form.auto_prune.data, 151 bootstrap=bootstrap, 152 homepage=form.homepage.data, 153 contact=form.contact.data, 154 disable_createrepo=form.disable_createrepo.data, 155 delete_after_days=form.delete_after_days.data, 156 multilib=form.multilib.data, 157 module_hotfixes=form.module_hotfixes.data, 158 ) 159 db.session.commit() 160 except (DuplicateException, 161 NonAdminCannotCreatePersistentProject, 162 NonAdminCannotDisableAutoPrunning) as err: 163 db.session.rollback() 164 raise err 165 return flask.jsonify(to_dict(copr))
166
167 168 @apiv3_ns.route("/project/edit/<ownername>/<projectname>", methods=PUT) 169 @api_login_required 170 -def edit_project(ownername, projectname):
171 copr = get_copr(ownername, projectname) 172 data = rename_fields(get_form_compatible_data()) 173 form = forms.CoprModifyForm(data, meta={'csrf': False}) 174 175 if not form.validate_on_submit(): 176 raise BadRequest(form.errors) 177 validate_chroots(get_input_dict(), MockChrootsLogic.get_multiple()) 178 179 for field in form: 180 if field.data is None or field.name in ["csrf_token", "chroots"]: 181 continue 182 if field.name not in data.keys(): 183 continue 184 setattr(copr, field.name, field.data) 185 186 if form.chroots.data: 187 CoprChrootsLogic.update_from_names( 188 flask.g.user, copr, form.chroots.data) 189 190 try: 191 CoprsLogic.update(flask.g.user, copr) 192 if copr.group: # load group.id 193 _ = copr.group.id 194 db.session.commit() 195 except (ActionInProgressException, 196 InsufficientRightsException, 197 NonAdminCannotDisableAutoPrunning) as ex: 198 db.session.rollback() 199 raise ex 200 201 return flask.jsonify(to_dict(copr))
202
203 204 @apiv3_ns.route("/project/fork/<ownername>/<projectname>", methods=PUT) 205 @api_login_required 206 -def fork_project(ownername, projectname):
207 copr = get_copr(ownername, projectname) 208 209 # @FIXME we want "ownername" from the outside, but our internal Form expects "owner" instead 210 data = get_form_compatible_data() 211 data["owner"] = data.get("ownername") 212 213 form = forms.CoprForkFormFactory \ 214 .create_form_cls(copr=copr, user=flask.g.user, groups=flask.g.user.user_groups)(data, meta={'csrf': False}) 215 216 if form.validate_on_submit() and copr: 217 try: 218 dstgroup = ([g for g in flask.g.user.user_groups if g.at_name == form.owner.data] or [None])[0] 219 if flask.g.user.name != form.owner.data and not dstgroup: 220 return ObjectNotFound("There is no such group: {}".format(form.owner.data)) 221 222 dst_copr = CoprsLogic.get(flask.g.user.name, form.name.data).all() 223 if dst_copr and form.confirm.data != True: 224 raise BadRequest("You are about to fork into existing project: {}\n" 225 "Please use --confirm if you really want to do this".format(form.name.data)) 226 fcopr, _ = ComplexLogic.fork_copr(copr, flask.g.user, dstname=form.name.data, 227 dstgroup=dstgroup) 228 db.session.commit() 229 230 except (ActionInProgressException, InsufficientRightsException) as err: 231 db.session.rollback() 232 raise err 233 else: 234 raise BadRequest(form.errors) 235 236 return flask.jsonify(to_dict(fcopr))
237
238 239 @apiv3_ns.route("/project/delete/<ownername>/<projectname>", methods=DELETE) 240 @api_login_required 241 -def delete_project(ownername, projectname):
242 copr = get_copr(ownername, projectname) 243 copr_dict = to_dict(copr) 244 form = forms.APICoprDeleteForm(meta={'csrf': False}) 245 246 if form.validate_on_submit() and copr: 247 try: 248 ComplexLogic.delete_copr(copr) 249 except (ActionInProgressException, 250 InsufficientRightsException) as err: 251 db.session.rollback() 252 raise err 253 else: 254 db.session.commit() 255 else: 256 raise BadRequest(form.errors) 257 return flask.jsonify(copr_dict)
258