Package coprs :: Package views :: Package api_ns :: Module api_general
[hide private]
[frames] | no frames]

Source Code for Module coprs.views.api_ns.api_general

  1  import base64 
  2  import datetime 
  3  from functools import wraps 
  4  import json 
  5  import os 
  6  import flask 
  7   
  8  from werkzeug import secure_filename 
  9   
 10  from coprs import db 
 11  from coprs import exceptions 
 12  from coprs import forms 
 13  from coprs import helpers 
 14  from coprs import models 
 15  from coprs.helpers import fix_protocol_for_backend 
 16  from coprs.logic.api_logic import MonitorWrapper 
 17  from coprs.logic.builds_logic import BuildsLogic 
 18  from coprs.logic.complex_logic import ComplexLogic 
 19  from coprs.logic.users_logic import UsersLogic 
 20  from coprs.logic.packages_logic import PackagesLogic 
 21   
 22  from coprs.views.misc import login_required, api_login_required 
 23   
 24  from coprs.views.api_ns import api_ns 
 25   
 26  from coprs.logic import builds_logic 
 27  from coprs.logic import coprs_logic 
 28  from coprs.logic.coprs_logic import CoprsLogic 
 29  from coprs.logic.actions_logic import ActionsLogic 
 30   
 31  from coprs.exceptions import (ActionInProgressException, 
 32                                InsufficientRightsException, 
 33                                DuplicateException, 
 34                                LegacyApiError, 
 35                                UnknownSourceTypeException) 
36 37 38 -def api_req_with_copr(f):
39 @wraps(f) 40 def wrapper(username, coprname, **kwargs): 41 if username.startswith("@"): 42 group_name = username[1:] 43 copr = ComplexLogic.get_group_copr_safe(group_name, coprname) 44 else: 45 copr = ComplexLogic.get_copr_safe(username, coprname) 46 47 return f(copr, **kwargs)
48 return wrapper 49
50 51 @api_ns.route("/") 52 -def api_home():
53 """ 54 Render the home page of the api. 55 This page provides information on how to call/use the API. 56 """ 57 58 return flask.render_template("api.html")
59 60 61 @api_ns.route("/new/", methods=["GET", "POST"])
62 @login_required 63 -def api_new_token():
64 """ 65 Generate a new API token for the current user. 66 """ 67 68 user = flask.g.user 69 copr64 = base64.b64encode(b"copr") + b"##" 70 api_login = helpers.generate_api_token( 71 flask.current_app.config["API_TOKEN_LENGTH"] - len(copr64)) 72 user.api_login = api_login 73 user.api_token = helpers.generate_api_token( 74 flask.current_app.config["API_TOKEN_LENGTH"]) 75 user.api_token_expiration = datetime.date.today() + \ 76 datetime.timedelta( 77 days=flask.current_app.config["API_TOKEN_EXPIRATION"]) 78 79 db.session.add(user) 80 db.session.commit() 81 return flask.redirect(flask.url_for("api_ns.api_home"))
82 83 84 @api_ns.route("/coprs/<username>/new/", methods=["POST"])
85 @api_login_required 86 -def api_new_copr(username):
87 """ 88 Receive information from the user on how to create its new copr, 89 check their validity and create the corresponding copr. 90 91 :arg name: the name of the copr to add 92 :arg chroots: a comma separated list of chroots to use 93 :kwarg repos: a comma separated list of repository that this copr 94 can use. 95 :kwarg initial_pkgs: a comma separated list of initial packages to 96 build in this new copr 97 98 """ 99 100 form = forms.CoprFormFactory.create_form_cls()(csrf_enabled=False) 101 infos = [] 102 103 # are there any arguments in POST which our form doesn't know? 104 # TODO: don't use WTFform for parsing and validation here 105 for post_key in flask.request.form.keys(): 106 if post_key not in form.__dict__.keys(): 107 infos.append("Unknown key '{key}' received.".format(key=post_key)) 108 109 if form.validate_on_submit(): 110 group = ComplexLogic.get_group_by_name_safe(username[1:]) if username[0] == "@" else None 111 112 try: 113 copr = CoprsLogic.add( 114 name=form.name.data.strip(), 115 repos=" ".join(form.repos.data.split()), 116 user=flask.g.user, 117 selected_chroots=form.selected_chroots, 118 description=form.description.data, 119 instructions=form.instructions.data, 120 check_for_duplicates=True, 121 disable_createrepo=form.disable_createrepo.data, 122 unlisted_on_hp=form.unlisted_on_hp.data, 123 build_enable_net=form.build_enable_net.data, 124 group=group, 125 persistent=form.persistent.data, 126 ) 127 infos.append("New project was successfully created.") 128 129 if form.initial_pkgs.data: 130 pkgs = form.initial_pkgs.data.split() 131 for pkg in pkgs: 132 builds_logic.BuildsLogic.add( 133 user=flask.g.user, 134 pkgs=pkg, 135 copr=copr) 136 137 infos.append("Initial packages were successfully " 138 "submitted for building.") 139 140 output = {"output": "ok", "message": "\n".join(infos)} 141 db.session.commit() 142 except (exceptions.DuplicateException, exceptions.NonAdminCannotCreatePersistentProject) as err: 143 db.session.rollback() 144 raise LegacyApiError(str(err)) 145 146 else: 147 errormsg = "Validation error\n" 148 if form.errors: 149 for field, emsgs in form.errors.items(): 150 errormsg += "- {0}: {1}\n".format(field, "\n".join(emsgs)) 151 152 errormsg = errormsg.replace('"', "'") 153 raise LegacyApiError(errormsg) 154 155 return flask.jsonify(output)
156 157 158 @api_ns.route("/coprs/<username>/<coprname>/delete/", methods=["POST"])
159 @api_login_required 160 @api_req_with_copr 161 -def api_copr_delete(copr):
162 """ Deletes selected user's project 163 """ 164 form = forms.CoprDeleteForm(csrf_enabled=False) 165 httpcode = 200 166 167 if form.validate_on_submit() and copr: 168 try: 169 ComplexLogic.delete_copr(copr) 170 except (exceptions.ActionInProgressException, 171 exceptions.InsufficientRightsException) as err: 172 173 db.session.rollback() 174 raise LegacyApiError(str(err)) 175 else: 176 message = "Project {} has been deleted.".format(copr.name) 177 output = {"output": "ok", "message": message} 178 db.session.commit() 179 else: 180 raise LegacyApiError("Invalid request: {0}".format(form.errors)) 181 182 return flask.jsonify(output)
183 184 185 @api_ns.route("/coprs/<username>/<coprname>/fork/", methods=["POST"])
186 @api_login_required 187 @api_req_with_copr 188 -def api_copr_fork(copr):
189 """ Fork the project and builds in it 190 """ 191 form = forms.CoprForkFormFactory\ 192 .create_form_cls(copr=copr, user=flask.g.user, groups=flask.g.user.user_groups)(csrf_enabled=False) 193 194 if form.validate_on_submit() and copr: 195 try: 196 dstgroup = ([g for g in flask.g.user.user_groups if g.at_name == form.owner.data] or [None])[0] 197 if flask.g.user.name != form.owner.data and not dstgroup: 198 return LegacyApiError("There is no such group: {}".format(form.owner.data)) 199 200 fcopr, created = ComplexLogic.fork_copr(copr, flask.g.user, dstname=form.name.data, dstgroup=dstgroup) 201 if created: 202 msg = ("Forking project {} for you into {}.\nPlease be aware that it may take a few minutes " 203 "to duplicate a backend data.".format(copr.full_name, fcopr.full_name)) 204 elif not created and form.confirm.data == True: 205 msg = ("Updating packages in {} from {}.\nPlease be aware that it may take a few minutes " 206 "to duplicate a backend data.".format(copr.full_name, fcopr.full_name)) 207 else: 208 raise LegacyApiError("You are about to fork into existing project: {}\n" 209 "Please use --confirm if you really want to do this".format(fcopr.full_name)) 210 211 output = {"output": "ok", "message": msg} 212 db.session.commit() 213 214 except (exceptions.ActionInProgressException, 215 exceptions.InsufficientRightsException) as err: 216 db.session.rollback() 217 raise LegacyApiError(str(err)) 218 else: 219 raise LegacyApiError("Invalid request: {0}".format(form.errors)) 220 221 return flask.jsonify(output)
222
223 224 @api_ns.route("/coprs/") 225 @api_ns.route("/coprs/<username>/") 226 -def api_coprs_by_owner(username=None):
227 """ Return the list of coprs owned by the given user. 228 username is taken either from GET params or from the URL itself 229 (in this order). 230 231 :arg username: the username of the person one would like to the 232 coprs of. 233 234 """ 235 username = flask.request.args.get("username", None) or username 236 if username is None: 237 raise LegacyApiError("Invalid request: missing `username` ") 238 239 release_tmpl = "{chroot.os_release}-{chroot.os_version}-{chroot.arch}" 240 241 if username.startswith("@"): 242 group_name = username[1:] 243 query = CoprsLogic.get_multiple() 244 query = CoprsLogic.filter_by_group_name(query, group_name) 245 else: 246 query = CoprsLogic.get_multiple_owned_by_username(username) 247 248 query = CoprsLogic.join_builds(query) 249 query = CoprsLogic.set_query_order(query) 250 251 repos = query.all() 252 output = {"output": "ok", "repos": []} 253 for repo in repos: 254 yum_repos = {} 255 for build in repo.builds: 256 if build.results: 257 for chroot in repo.active_chroots: 258 release = release_tmpl.format(chroot=chroot) 259 yum_repos[release] = fix_protocol_for_backend( 260 os.path.join(build.results, release + '/')) 261 break 262 263 output["repos"].append({"name": repo.name, 264 "additional_repos": repo.repos, 265 "yum_repos": yum_repos, 266 "description": repo.description, 267 "instructions": repo.instructions, 268 "persistent": repo.persistent, 269 "unlisted_on_hp": repo.unlisted_on_hp 270 }) 271 272 return flask.jsonify(output)
273
274 275 @api_ns.route("/coprs/<username>/<coprname>/detail/") 276 @api_req_with_copr 277 -def api_coprs_by_owner_detail(copr):
278 """ Return detail of one project. 279 280 :arg username: the username of the person one would like to the 281 coprs of. 282 :arg coprname: the name of project. 283 284 """ 285 release_tmpl = "{chroot.os_release}-{chroot.os_version}-{chroot.arch}" 286 output = {"output": "ok", "detail": {}} 287 yum_repos = {} 288 289 build = models.Build.query.filter(models.Build.results != None).first() 290 if build: 291 for chroot in copr.active_chroots: 292 release = release_tmpl.format(chroot=chroot) 293 yum_repos[release] = fix_protocol_for_backend( 294 os.path.join(build.results, release + '/')) 295 296 output["detail"] = { 297 "name": copr.name, 298 "additional_repos": copr.repos, 299 "yum_repos": yum_repos, 300 "description": copr.description, 301 "instructions": copr.instructions, 302 "last_modified": builds_logic.BuildsLogic.last_modified(copr), 303 "auto_createrepo": copr.auto_createrepo, 304 "persistent": copr.persistent, 305 "unlisted_on_hp": copr.unlisted_on_hp 306 } 307 return flask.jsonify(output)
308 309 310 @api_ns.route("/coprs/<username>/<coprname>/new_build/", methods=["POST"])
311 @api_login_required 312 @api_req_with_copr 313 -def copr_new_build(copr):
314 form = forms.BuildFormUrlFactory(copr.active_chroots)(csrf_enabled=False) 315 316 def create_new_build(): 317 # create separate build for each package 318 pkgs = form.pkgs.data.split("\n") 319 return [BuildsLogic.create_new_from_url( 320 flask.g.user, copr, 321 srpm_url=pkg, 322 chroot_names=form.selected_chroots, 323 background=form.background.data, 324 ) for pkg in pkgs]
325 return process_creating_new_build(copr, form, create_new_build) 326 327 328 @api_ns.route("/coprs/<username>/<coprname>/new_build_upload/", methods=["POST"])
329 @api_login_required 330 @api_req_with_copr 331 -def copr_new_build_upload(copr):
332 form = forms.BuildFormUploadFactory(copr.active_chroots)(csrf_enabled=False) 333 334 def create_new_build(): 335 return BuildsLogic.create_new_from_upload( 336 flask.g.user, copr, 337 f_uploader=lambda path: form.pkgs.data.save(path), 338 orig_filename=secure_filename(form.pkgs.data.filename), 339 chroot_names=form.selected_chroots, 340 background=form.background.data, 341 )
342 return process_creating_new_build(copr, form, create_new_build) 343 344 345 @api_ns.route("/coprs/<username>/<coprname>/new_build_pypi/", methods=["POST"])
346 @api_login_required 347 @api_req_with_copr 348 -def copr_new_build_pypi(copr):
349 form = forms.BuildFormPyPIFactory(copr.active_chroots)(csrf_enabled=False) 350 351 # TODO: automatically prepopulate all form fields with their defaults 352 if not form.python_versions.data: 353 form.python_versions.data = form.python_versions.default 354 355 def create_new_build(): 356 return BuildsLogic.create_new_from_pypi( 357 flask.g.user, 358 copr, 359 form.pypi_package_name.data, 360 form.pypi_package_version.data, 361 form.python_versions.data, 362 form.selected_chroots, 363 background=form.background.data, 364 )
365 return process_creating_new_build(copr, form, create_new_build) 366 367 368 @api_ns.route("/coprs/<username>/<coprname>/new_build_tito/", methods=["POST"])
369 @api_login_required 370 @api_req_with_copr 371 -def copr_new_build_tito(copr):
372 form = forms.BuildFormTitoFactory(copr.active_chroots)(csrf_enabled=False) 373 374 def create_new_build(): 375 return BuildsLogic.create_new_from_tito( 376 flask.g.user, 377 copr, 378 form.git_url.data, 379 form.git_directory.data, 380 form.git_branch.data, 381 form.tito_test.data, 382 form.selected_chroots, 383 background=form.background.data, 384 )
385 return process_creating_new_build(copr, form, create_new_build) 386 387 388 @api_ns.route("/coprs/<username>/<coprname>/new_build_mock/", methods=["POST"])
389 @api_login_required 390 @api_req_with_copr 391 -def copr_new_build_mock(copr):
392 form = forms.BuildFormMockFactory(copr.active_chroots)(csrf_enabled=False) 393 394 def create_new_build(): 395 return BuildsLogic.create_new_from_mock( 396 flask.g.user, 397 copr, 398 form.scm_type.data, 399 form.scm_url.data, 400 form.scm_branch.data, 401 form.spec.data, 402 form.selected_chroots, 403 background=form.background.data, 404 )
405 return process_creating_new_build(copr, form, create_new_build) 406 407 408 @api_ns.route("/coprs/<username>/<coprname>/new_build_rubygems/", methods=["POST"])
409 @api_login_required 410 @api_req_with_copr 411 -def copr_new_build_rubygems(copr):
412 form = forms.BuildFormRubyGemsFactory(copr.active_chroots)(csrf_enabled=False) 413 414 def create_new_build(): 415 return BuildsLogic.create_new_from_rubygems( 416 flask.g.user, 417 copr, 418 form.gem_name.data, 419 form.selected_chroots, 420 background=form.background.data, 421 )
422 return process_creating_new_build(copr, form, create_new_build) 423
424 425 -def process_creating_new_build(copr, form, create_new_build):
426 infos = [] 427 428 # are there any arguments in POST which our form doesn't know? 429 for post_key in flask.request.form.keys(): 430 if post_key not in form.__dict__.keys(): 431 infos.append("Unknown key '{key}' received.".format(key=post_key)) 432 433 if not form.validate_on_submit(): 434 raise LegacyApiError("Invalid request: bad request parameters: {0}".format(form.errors)) 435 436 if not flask.g.user.can_build_in(copr): 437 raise LegacyApiError("Invalid request: user {} is not allowed to build in the copr: {}" 438 .format(flask.g.user.username, copr.full_name)) 439 440 # create a new build 441 try: 442 # From URLs it can be created multiple builds at once 443 # so it can return a list 444 build = create_new_build() 445 db.session.commit() 446 ids = [build.id] if type(build) != list else [b.id for b in build] 447 infos.append("Build was added to {0}.".format(copr.name)) 448 449 except (ActionInProgressException, InsufficientRightsException) as e: 450 raise LegacyApiError("Invalid request: {}".format(e)) 451 452 output = {"output": "ok", 453 "ids": ids, 454 "message": "\n".join(infos)} 455 456 return flask.jsonify(output)
457 458 459 @api_ns.route("/coprs/build_status/<int:build_id>/", methods=["GET"])
460 @api_login_required 461 -def build_status(build_id):
462 build = ComplexLogic.get_build_safe(build_id) 463 output = {"output": "ok", 464 "status": build.state} 465 return flask.jsonify(output)
466 467 468 @api_ns.route("/coprs/build_detail/<int:build_id>/", methods=["GET"]) 469 @api_ns.route("/coprs/build/<int:build_id>/", methods=["GET"])
470 -def build_detail(build_id):
471 build = ComplexLogic.get_build_safe(build_id) 472 473 chroots = {} 474 results_by_chroot = {} 475 for chroot in build.build_chroots: 476 chroots[chroot.name] = chroot.state 477 results_by_chroot[chroot.name] = chroot.result_dir_url 478 479 built_packages = None 480 if build.built_packages: 481 built_packages = build.built_packages.split("\n") 482 483 output = { 484 "output": "ok", 485 "status": build.state, 486 "project": build.copr.name, 487 "owner": build.copr.owner_name, 488 "results": build.results, 489 "built_pkgs": built_packages, 490 "src_version": build.pkg_version, 491 "chroots": chroots, 492 "submitted_on": build.submitted_on, 493 "started_on": build.min_started_on, 494 "ended_on": build.max_ended_on, 495 "src_pkg": build.pkgs, 496 "submitted_by": build.user.name, 497 "results_by_chroot": results_by_chroot 498 } 499 return flask.jsonify(output)
500 501 502 @api_ns.route("/coprs/cancel_build/<int:build_id>/", methods=["POST"])
503 @api_login_required 504 -def cancel_build(build_id):
505 build = ComplexLogic.get_build_safe(build_id) 506 507 try: 508 builds_logic.BuildsLogic.cancel_build(flask.g.user, build) 509 db.session.commit() 510 except exceptions.InsufficientRightsException as e: 511 raise LegacyApiError("Invalid request: {}".format(e)) 512 513 output = {'output': 'ok', 'status': "Build canceled"} 514 return flask.jsonify(output)
515 516 517 @api_ns.route('/coprs/<username>/<coprname>/modify/', methods=["POST"])
518 @api_login_required 519 @api_req_with_copr 520 -def copr_modify(copr):
521 form = forms.CoprModifyForm(csrf_enabled=False) 522 523 if not form.validate_on_submit(): 524 raise LegacyApiError("Invalid request: {0}".format(form.errors)) 525 526 # .raw_data needs to be inspected to figure out whether the field 527 # was not sent or was sent empty 528 if form.description.raw_data and len(form.description.raw_data): 529 copr.description = form.description.data 530 if form.instructions.raw_data and len(form.instructions.raw_data): 531 copr.instructions = form.instructions.data 532 if form.repos.raw_data and len(form.repos.raw_data): 533 copr.repos = form.repos.data 534 if form.disable_createrepo.raw_data and len(form.disable_createrepo.raw_data): 535 copr.disable_createrepo = form.disable_createrepo.data 536 537 if "unlisted_on_hp" in flask.request.form != None: 538 copr.unlisted_on_hp = form.unlisted_on_hp.data 539 if "build_enable_net" in flask.request.form != None: 540 copr.build_enable_net = form.build_enable_net.data 541 542 try: 543 CoprsLogic.update(flask.g.user, copr) 544 if copr.group: # load group.id 545 _ = copr.group.id 546 db.session.commit() 547 except (exceptions.ActionInProgressException, exceptions.InsufficientRightsException) as e: 548 db.session.rollback() 549 raise LegacyApiError("Invalid request: {}".format(e)) 550 551 output = { 552 'output': 'ok', 553 'description': copr.description, 554 'instructions': copr.instructions, 555 'repos': copr.repos, 556 } 557 558 return flask.jsonify(output)
559 560 561 @api_ns.route('/coprs/<username>/<coprname>/modify/<chrootname>/', methods=["POST"])
562 @api_login_required 563 @api_req_with_copr 564 -def copr_modify_chroot(copr, chrootname):
565 form = forms.ModifyChrootForm(csrf_enabled=False) 566 # chroot = coprs_logic.MockChrootsLogic.get_from_name(chrootname, active_only=True).first() 567 chroot = ComplexLogic.get_copr_chroot_safe(copr, chrootname) 568 569 if not form.validate_on_submit(): 570 raise LegacyApiError("Invalid request: {0}".format(form.errors)) 571 else: 572 coprs_logic.CoprChrootsLogic.update_chroot(flask.g.user, chroot, form.buildroot_pkgs.data) 573 db.session.commit() 574 575 output = {'output': 'ok', 'buildroot_pkgs': chroot.buildroot_pkgs} 576 return flask.jsonify(output)
577 578 579 @api_ns.route('/coprs/<username>/<coprname>/detail/<chrootname>/', methods=["GET"])
580 @api_req_with_copr 581 -def copr_chroot_details(copr, chrootname):
582 chroot = ComplexLogic.get_copr_chroot_safe(copr, chrootname) 583 output = {'output': 'ok', 'buildroot_pkgs': chroot.buildroot_pkgs} 584 return flask.jsonify(output)
585
586 587 @api_ns.route("/coprs/search/") 588 @api_ns.route("/coprs/search/<project>/") 589 -def api_coprs_search_by_project(project=None):
590 """ Return the list of coprs found in search by the given text. 591 project is taken either from GET params or from the URL itself 592 (in this order). 593 594 :arg project: the text one would like find for coprs. 595 596 """ 597 project = flask.request.args.get("project", None) or project 598 if not project: 599 raise LegacyApiError("No project found.") 600 601 try: 602 query = CoprsLogic.get_multiple_fulltext(project) 603 604 repos = query.all() 605 output = {"output": "ok", "repos": []} 606 for repo in repos: 607 output["repos"].append({"username": repo.user.name, 608 "coprname": repo.name, 609 "description": repo.description}) 610 except ValueError as e: 611 raise LegacyApiError("Server error: {}".format(e)) 612 613 return flask.jsonify(output)
614
615 616 @api_ns.route("/playground/list/") 617 -def playground_list():
618 """ Return list of coprs which are part of playground """ 619 query = CoprsLogic.get_playground() 620 repos = query.all() 621 output = {"output": "ok", "repos": []} 622 for repo in repos: 623 output["repos"].append({"username": repo.owner_name, 624 "coprname": repo.name, 625 "chroots": [chroot.name for chroot in repo.active_chroots]}) 626 627 jsonout = flask.jsonify(output) 628 jsonout.status_code = 200 629 return jsonout
630 631 632 @api_ns.route("/coprs/<username>/<coprname>/monitor/", methods=["GET"])
633 @api_req_with_copr 634 -def monitor(copr):
635 monitor_data = builds_logic.BuildsMonitorLogic.get_monitor_data(copr) 636 output = MonitorWrapper(copr, monitor_data).to_dict() 637 return flask.jsonify(output)
638 639 ############################################################################### 640 641 @api_ns.route("/coprs/<username>/<coprname>/package/add/<source_type_text>/", methods=["POST"])
642 @api_login_required 643 @api_req_with_copr 644 -def copr_add_package(copr, source_type_text):
645 return process_package_add_or_edit(copr, source_type_text)
646 647 648 @api_ns.route("/coprs/<username>/<coprname>/package/<package_name>/edit/<source_type_text>/", methods=["POST"])
649 @api_login_required 650 @api_req_with_copr 651 -def copr_edit_package(copr, package_name, source_type_text):
652 try: 653 package = PackagesLogic.get(copr.id, package_name)[0] 654 except IndexError: 655 raise LegacyApiError("Package {name} does not exists in copr {copr}.".format(name=package_name, copr=copr.full_name)) 656 return process_package_add_or_edit(copr, source_type_text, package=package)
657
658 659 -def process_package_add_or_edit(copr, source_type_text, package=None):
660 try: 661 form = forms.get_package_form_cls_by_source_type_text(source_type_text)(csrf_enabled=False) 662 except UnknownSourceTypeException: 663 raise LegacyApiError("Unsupported package source type {source_type_text}".format(source_type_text=source_type_text)) 664 665 if form.validate_on_submit(): 666 if not package: 667 try: 668 package = PackagesLogic.add(flask.app.g.user, copr, form.package_name.data) 669 except InsufficientRightsException: 670 raise LegacyApiError("Insufficient permissions.") 671 except DuplicateException: 672 raise LegacyApiError("Package {0} already exists in copr {1}.".format(form.package_name.data, copr.full_name)) 673 674 package.source_type = helpers.BuildSourceEnum(source_type_text) 675 package.webhook_rebuild = form.webhook_rebuild.data 676 package.source_json = form.source_json 677 678 db.session.add(package) 679 db.session.commit() 680 else: 681 raise LegacyApiError(form.errors) 682 683 return flask.jsonify({ 684 "output": "ok", 685 "message": "Create or edit operation was successful.", 686 "package": package.to_dict(), 687 })
688
689 690 -def get_package_record_params():
691 params = {} 692 if flask.request.args.get('with_latest_build'): 693 params['with_latest_build'] = True 694 if flask.request.args.get('with_latest_succeeded_build'): 695 params['with_latest_succeeded_build'] = True 696 if flask.request.args.get('with_all_builds'): 697 params['with_all_builds'] = True 698 return params
699
700 701 -def generate_package_list(query, params):
702 """ 703 A lagging generator to stream JSON so we don't have to hold everything in memory 704 This is a little tricky, as we need to omit the last comma to make valid JSON, 705 thus we use a lagging generator, similar to http://stackoverflow.com/questions/1630320/ 706 """ 707 packages = query.__iter__() 708 try: 709 prev_package = next(packages) # get first result 710 except StopIteration: 711 # StopIteration here means the length was zero, so yield a valid packages doc and stop 712 yield '{"packages": []}' 713 raise StopIteration 714 # We have some packages. First, yield the opening json 715 yield '{"packages": [' 716 # Iterate over the packages 717 for package in packages: 718 yield json.dumps(prev_package.to_dict(**params)) + ', ' 719 prev_package = package 720 # Now yield the last iteration without comma but with the closing brackets 721 yield json.dumps(prev_package.to_dict(**params)) + ']}'
722 723 724 @api_ns.route("/coprs/<username>/<coprname>/package/list/", methods=["GET"])
725 @api_req_with_copr 726 -def copr_list_packages(copr):
727 packages = PackagesLogic.get_all(copr.id) 728 params = get_package_record_params() 729 return flask.Response(generate_package_list(packages, params), content_type='application/json')
730 #return flask.jsonify({"packages": [package.to_dict(**params) for package in packages]}) 731 732 733 @api_ns.route("/coprs/<username>/<coprname>/package/get/<package_name>/", methods=["GET"])
734 @api_req_with_copr 735 -def copr_get_package(copr, package_name):
736 try: 737 package = PackagesLogic.get(copr.id, package_name)[0] 738 except IndexError: 739 raise LegacyApiError("No package with name {name} in copr {copr}".format(name=package_name, copr=copr.name)) 740 741 params = get_package_record_params() 742 return flask.jsonify({'package': package.to_dict(**params)})
743 744 745 @api_ns.route("/coprs/<username>/<coprname>/package/delete/<package_name>/", methods=["POST"])
746 @api_login_required 747 @api_req_with_copr 748 -def copr_delete_package(copr, package_name):
749 try: 750 package = PackagesLogic.get(copr.id, package_name)[0] 751 except IndexError: 752 raise LegacyApiError("No package with name {name} in copr {copr}".format(name=package_name, copr=copr.name)) 753 754 try: 755 PackagesLogic.delete_package(flask.g.user, package) 756 db.session.commit() 757 except (InsufficientRightsException, ActionInProgressException) as e: 758 raise LegacyApiError(str(e)) 759 760 return flask.jsonify({ 761 "output": "ok", 762 "message": "Package was successfully deleted.", 763 'package': package.to_dict(), 764 })
765 766 767 @api_ns.route("/coprs/<username>/<coprname>/package/reset/<package_name>/", methods=["POST"])
768 @api_login_required 769 @api_req_with_copr 770 -def copr_reset_package(copr, package_name):
771 try: 772 package = PackagesLogic.get(copr.id, package_name)[0] 773 except IndexError: 774 raise LegacyApiError("No package with name {name} in copr {copr}".format(name=package_name, copr=copr.name)) 775 776 try: 777 PackagesLogic.reset_package(flask.g.user, package) 778 db.session.commit() 779 except InsufficientRightsException as e: 780 raise LegacyApiError(str(e)) 781 782 return flask.jsonify({ 783 "output": "ok", 784 "message": "Package's default source was successfully reseted.", 785 'package': package.to_dict(), 786 })
787 788 789 @api_ns.route("/coprs/<username>/<coprname>/package/build/<package_name>/", methods=["POST"])
790 @api_login_required 791 @api_req_with_copr 792 -def copr_build_package(copr, package_name):
793 form = forms.BuildFormRebuildFactory.create_form_cls(copr.active_chroots)(csrf_enabled=False) 794 795 try: 796 package = PackagesLogic.get(copr.id, package_name)[0] 797 except IndexError: 798 raise LegacyApiError("No package with name {name} in copr {copr}".format(name=package_name, copr=copr.name)) 799 800 if form.validate_on_submit(): 801 try: 802 build = PackagesLogic.build_package(flask.g.user, copr, package, form.selected_chroots, **form.data) 803 db.session.commit() 804 except (InsufficientRightsException, ActionInProgressException, NoPackageSourceException) as e: 805 raise LegacyApiError(str(e)) 806 else: 807 raise LegacyApiError(form.errors) 808 809 return flask.jsonify({ 810 "output": "ok", 811 "ids": [build.id], 812 "message": "Build was added to {0}.".format(copr.name) 813 })
814 815 816 @api_ns.route("/coprs/<username>/<coprname>/module/build/", methods=["POST"])
817 @api_login_required 818 @api_req_with_copr 819 -def copr_build_module(copr):
820 form = forms.ModuleFormUploadFactory(csrf_enabled=False) 821 if not form.validate_on_submit(): 822 # @TODO Prettier error 823 raise LegacyApiError(form.errors) 824 825 modulemd = form.modulemd.data.read() 826 ActionsLogic.send_build_module(copr, modulemd) 827 db.session.commit() 828 829 return flask.jsonify({ 830 "output": "ok", 831 "message": "Module build was submitted", 832 "modulemd": modulemd, 833 })
834