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