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