Package coprs :: Package views :: Package coprs_ns :: Module coprs_general
[hide private]
[frames] | no frames]

Source Code for Module coprs.views.coprs_ns.coprs_general

  1  # coding: utf-8 
  2   
  3  import os 
  4  import time 
  5  import os 
  6  import re 
  7  import uuid 
  8  import subprocess 
  9  from six.moves.urllib.parse import urljoin 
 10   
 11  import flask 
 12  from flask import render_template, url_for, stream_with_context 
 13  import platform 
 14  import smtplib 
 15  import sqlalchemy 
 16  from email.mime.text import MIMEText 
 17  from itertools import groupby 
 18   
 19  from coprs import app 
 20  from coprs import db 
 21  from coprs import rcp 
 22  from coprs import exceptions 
 23  from coprs import forms 
 24  from coprs import helpers 
 25  from coprs import models 
 26  from coprs.exceptions import ObjectNotFound 
 27  from coprs.logic.coprs_logic import CoprsLogic 
 28  from coprs.logic.stat_logic import CounterStatLogic 
 29  from coprs.logic.users_logic import UsersLogic 
 30  from coprs.rmodels import TimedStatEvents 
 31   
 32  from coprs.logic.complex_logic import ComplexLogic 
 33   
 34  from coprs.views.misc import login_required, page_not_found, req_with_copr, req_with_copr, generic_error 
 35   
 36  from coprs.views.coprs_ns import coprs_ns 
 37  from coprs.views.groups_ns import groups_ns 
 38   
 39  from coprs.logic import builds_logic, coprs_logic, actions_logic, users_logic 
 40  from coprs.helpers import parse_package_name, generate_repo_url, CHROOT_RPMS_DL_STAT_FMT, CHROOT_REPO_MD_DL_STAT_FMT, \ 
 41      str2bool, url_for_copr_view 
42 43 44 -def url_for_copr_details(copr):
45 return url_for_copr_view( 46 "coprs_ns.copr_detail", 47 "coprs_ns.group_copr_detail", 48 copr)
49
50 51 -def url_for_copr_edit(copr):
52 return url_for_copr_view( 53 "coprs_ns.copr_edit", 54 "coprs_ns.group_copr_edit", 55 copr)
56
57 58 @coprs_ns.route("/", defaults={"page": 1}) 59 @coprs_ns.route("/<int:page>/") 60 -def coprs_show(page=1):
61 query = CoprsLogic.get_multiple(include_unlisted_on_hp=False) 62 query = CoprsLogic.set_query_order(query, desc=True) 63 64 paginator = helpers.Paginator(query, query.count(), page) 65 66 coprs = paginator.sliced_query 67 68 # flask.g.user is none when no user is logged - showing builds from everyone 69 # TODO: builds_logic.BuildsLogic.get_recent_tasks(flask.g.user, 5) takes too much time, optimize sql 70 # users_builds = builds_logic.BuildsLogic.get_recent_tasks(flask.g.user, 5) 71 users_builds = builds_logic.BuildsLogic.get_recent_tasks(None, 5) 72 73 return flask.render_template("coprs/show/all.html", 74 coprs=coprs, 75 paginator=paginator, 76 tasks_info=ComplexLogic.get_queues_size(), 77 users_builds=users_builds)
78
79 80 @coprs_ns.route("/<username>/", defaults={"page": 1}) 81 @coprs_ns.route("/<username>/<int:page>/") 82 -def coprs_by_user(username=None, page=1):
83 user = users_logic.UsersLogic.get(username).first() 84 if not user: 85 return page_not_found( 86 "User {0} does not exist.".format(username)) 87 88 query = CoprsLogic.get_multiple_owned_by_username(username) 89 query = CoprsLogic.filter_without_group_projects(query) 90 query = CoprsLogic.set_query_order(query, desc=True) 91 92 paginator = helpers.Paginator(query, query.count(), page) 93 94 coprs = paginator.sliced_query 95 96 # flask.g.user is none when no user is logged - showing builds from everyone 97 users_builds = builds_logic.BuildsLogic.get_recent_tasks(flask.g.user, 5) 98 99 return flask.render_template("coprs/show/user.html", 100 user=user, 101 coprs=coprs, 102 paginator=paginator, 103 tasks_info=ComplexLogic.get_queues_size(), 104 users_builds=users_builds)
105
106 107 @coprs_ns.route("/fulltext/", defaults={"page": 1}) 108 @coprs_ns.route("/fulltext/<int:page>/") 109 -def coprs_fulltext_search(page=1):
110 fulltext = flask.request.args.get("fulltext", "") 111 try: 112 query = coprs_logic.CoprsLogic.get_multiple_fulltext(fulltext) 113 except ValueError as e: 114 flask.flash(str(e), "error") 115 return flask.redirect(flask.request.referrer or 116 flask.url_for("coprs_ns.coprs_show")) 117 118 paginator = helpers.Paginator(query, query.count(), page, 119 additional_params={"fulltext": fulltext}) 120 121 coprs = paginator.sliced_query 122 return render_template( 123 "coprs/show/fulltext.html", 124 coprs=coprs, 125 paginator=paginator, 126 fulltext=fulltext, 127 tasks_info=ComplexLogic.get_queues_size(), 128 )
129
130 131 @coprs_ns.route("/<username>/add/") 132 @login_required 133 -def copr_add(username):
134 form = forms.CoprFormFactory.create_form_cls()() 135 136 return flask.render_template("coprs/add.html", form=form)
137
138 139 @coprs_ns.route("/g/<group_name>/add/") 140 @login_required 141 -def group_copr_add(group_name):
142 group = ComplexLogic.get_group_by_name_safe(group_name) 143 form = forms.CoprFormFactory.create_form_cls()() 144 145 return flask.render_template( 146 "coprs/group_add.html", form=form, group=group)
147 148 149 @coprs_ns.route("/g/<group_name>/new/", methods=["POST"])
150 @login_required 151 -def group_copr_new(group_name):
152 group = ComplexLogic.get_group_by_name_safe(group_name) 153 form = forms.CoprFormFactory.create_form_cls(group=group)() 154 155 if form.validate_on_submit(): 156 try: 157 copr = coprs_logic.CoprsLogic.add( 158 flask.g.user, 159 name=form.name.data, 160 homepage=form.homepage.data, 161 contact=form.contact.data, 162 repos=form.repos.data.replace("\n", " "), 163 selected_chroots=form.selected_chroots, 164 description=form.description.data, 165 instructions=form.instructions.data, 166 disable_createrepo=form.disable_createrepo.data, 167 build_enable_net=form.build_enable_net.data, 168 unlisted_on_hp=form.unlisted_on_hp.data, 169 group=group, 170 persistent=form.persistent.data, 171 ) 172 except (exceptions.DuplicateException, exceptions.NonAdminCannotCreatePersistentProject) as e: 173 flask.flash(str(e), "error") 174 return flask.render_template("coprs/group_add.html", form=form, group=group) 175 176 db.session.add(copr) 177 db.session.commit() 178 after_the_project_creation(copr, form) 179 180 return flask.redirect(url_for_copr_details(copr)) 181 else: 182 return flask.render_template("coprs/group_add.html", form=form, group=group)
183 184 185 @coprs_ns.route("/<username>/new/", methods=["POST"])
186 @login_required 187 -def copr_new(username):
188 """ 189 Receive information from the user on how to create its new copr 190 and create it accordingly. 191 """ 192 193 form = forms.CoprFormFactory.create_form_cls()() 194 if form.validate_on_submit(): 195 try: 196 copr = coprs_logic.CoprsLogic.add( 197 flask.g.user, 198 name=form.name.data, 199 homepage=form.homepage.data, 200 contact=form.contact.data, 201 repos=form.repos.data.replace("\n", " "), 202 selected_chroots=form.selected_chroots, 203 description=form.description.data, 204 instructions=form.instructions.data, 205 disable_createrepo=form.disable_createrepo.data, 206 build_enable_net=form.build_enable_net.data, 207 unlisted_on_hp=form.unlisted_on_hp.data, 208 persistent=form.persistent.data, 209 ) 210 except (exceptions.DuplicateException, exceptions.NonAdminCannotCreatePersistentProject) as e: 211 flask.flash(str(e), "error") 212 return flask.render_template("coprs/add.html", form=form) 213 214 db.session.commit() 215 after_the_project_creation(copr, form) 216 217 return flask.redirect(url_for_copr_details(copr)) 218 else: 219 return flask.render_template("coprs/add.html", form=form)
220
221 222 -def after_the_project_creation(copr, form):
223 flask.flash("New project has been created successfully.", "success") 224 _check_rpmfusion(copr.repos) 225 if form.initial_pkgs.data: 226 pkgs = form.initial_pkgs.data.replace("\n", " ").split(" ") 227 228 # validate (and skip bad) urls 229 bad_urls = [] 230 for pkg in pkgs: 231 if not re.match("^.*\.src\.rpm$", pkg): 232 bad_urls.append(pkg) 233 flask.flash("Bad url: {0} (skipped)".format(pkg)) 234 for bad_url in bad_urls: 235 pkgs.remove(bad_url) 236 237 if not pkgs: 238 flask.flash("No initial packages submitted") 239 else: 240 # build each package as a separate build 241 for pkg in pkgs: 242 builds_logic.BuildsLogic.add( 243 flask.g.user, 244 pkgs=pkg, 245 copr=copr, 246 enable_net=form.build_enable_net.data 247 ) 248 249 db.session.commit() 250 flask.flash("Initial packages were successfully submitted " 251 "for building.")
252
253 254 @coprs_ns.route("/<username>/<coprname>/report-abuse") 255 @req_with_copr 256 -def copr_report_abuse(copr):
257 return render_copr_report_abuse(copr)
258
259 260 @coprs_ns.route("/g/<group_name>/<coprname>/report-abuse") 261 @req_with_copr 262 -def group_copr_report_abuse(copr):
263 return render_copr_report_abuse(copr)
264
265 266 -def render_copr_report_abuse(copr):
267 form = forms.CoprLegalFlagForm() 268 return render_template("coprs/report_abuse.html", copr=copr, form=form)
269
270 271 @coprs_ns.route("/g/<group_name>/<coprname>/") 272 @req_with_copr 273 -def group_copr_detail(copr):
274 return render_copr_detail(copr)
275
276 277 @coprs_ns.route("/<username>/<coprname>/") 278 @req_with_copr 279 -def copr_detail(copr):
280 if copr.is_a_group_project: 281 return flask.redirect(url_for_copr_details(copr)) 282 return render_copr_detail(copr)
283
284 285 -def render_copr_detail(copr):
286 repo_dl_stat = CounterStatLogic.get_copr_repo_dl_stat(copr) 287 form = forms.CoprLegalFlagForm() 288 repos_info = {} 289 for chroot in copr.active_chroots: 290 # chroot_rpms_dl_stat_key = CHROOT_REPO_MD_DL_STAT_FMT.format( 291 # copr_user=copr.user.name, 292 # copr_project_name=copr.name, 293 # copr_chroot=chroot.name, 294 # ) 295 chroot_rpms_dl_stat_key = CHROOT_RPMS_DL_STAT_FMT.format( 296 copr_user=copr.user.name, 297 copr_project_name=copr.name, 298 copr_chroot=chroot.name, 299 ) 300 chroot_rpms_dl_stat = TimedStatEvents.get_count( 301 rconnect=rcp.get_connection(), 302 name=chroot_rpms_dl_stat_key, 303 ) 304 305 if chroot.name_release not in repos_info: 306 repos_info[chroot.name_release] = { 307 "name_release": chroot.name_release, 308 "name_release_human": chroot.name_release_human, 309 "os_release": chroot.os_release, 310 "os_version": chroot.os_version, 311 "arch_list": [chroot.arch], 312 "repo_file": "{}-{}.repo".format(copr.repo_id, chroot.name_release), 313 "dl_stat": repo_dl_stat[chroot.name_release], 314 "rpm_dl_stat": { 315 chroot.arch: chroot_rpms_dl_stat 316 } 317 } 318 else: 319 repos_info[chroot.name_release]["arch_list"].append(chroot.arch) 320 repos_info[chroot.name_release]["rpm_dl_stat"][chroot.arch] = chroot_rpms_dl_stat 321 repos_info_list = sorted(repos_info.values(), key=lambda rec: rec["name_release"]) 322 builds = builds_logic.BuildsLogic.get_multiple_by_copr(copr=copr).limit(1).all() 323 324 return flask.render_template( 325 "coprs/detail/overview.html", 326 copr=copr, 327 user=flask.g.user, 328 form=form, 329 repo_dl_stat=repo_dl_stat, 330 repos_info_list=repos_info_list, 331 latest_build=builds[0] if len(builds) == 1 else None, 332 )
333
334 335 @coprs_ns.route("/<username>/<coprname>/permissions/") 336 @req_with_copr 337 -def copr_permissions(copr):
338 permissions = coprs_logic.CoprPermissionsLogic.get_for_copr(copr).all() 339 if flask.g.user: 340 user_perm = flask.g.user.permissions_for_copr(copr) 341 else: 342 user_perm = None 343 344 permissions_applier_form = None 345 permissions_form = None 346 347 # generate a proper form for displaying 348 if flask.g.user: 349 # https://github.com/ajford/flask-wtf/issues/58 350 permissions_applier_form = \ 351 forms.PermissionsApplierFormFactory.create_form_cls( 352 user_perm)(formdata=None) 353 354 if flask.g.user.can_edit(copr): 355 permissions_form = forms.PermissionsFormFactory.create_form_cls( 356 permissions)() 357 358 return flask.render_template( 359 "coprs/detail/settings/permissions.html", 360 copr=copr, 361 permissions_form=permissions_form, 362 permissions_applier_form=permissions_applier_form, 363 permissions=permissions, 364 current_user_permissions=user_perm)
365
366 367 -def render_copr_webhooks(copr):
368 if not copr.webhook_secret: 369 copr.webhook_secret = uuid.uuid4() 370 db.session.add(copr) 371 db.session.commit() 372 373 github_url = "https://{}/webhooks/github/{}/{}/".format( 374 app.config["PUBLIC_COPR_HOSTNAME"], 375 copr.id, 376 copr.webhook_secret) 377 378 return flask.render_template( 379 "coprs/detail/settings/webhooks.html", 380 copr=copr, github_url=github_url)
381
382 383 @coprs_ns.route("/g/<group_name>/<coprname>/webhooks/") 384 @login_required 385 @req_with_copr 386 -def group_copr_webhooks(copr):
387 return render_copr_webhooks(copr)
388
389 390 @coprs_ns.route("/<username>/<coprname>/webhooks/") 391 @login_required 392 @req_with_copr 393 -def copr_webhooks(copr):
394 return render_copr_webhooks(copr)
395
396 397 -def render_copr_edit(copr, form, view):
398 if not form: 399 form = forms.CoprFormFactory.create_form_cls( 400 copr.mock_chroots)(obj=copr) 401 return flask.render_template( 402 "coprs/detail/settings/edit.html", 403 copr=copr, form=form, view=view)
404
405 406 @coprs_ns.route("/g/<group_name>/<coprname>/edit/") 407 @login_required 408 @req_with_copr 409 -def group_copr_edit(copr, form=None):
410 return render_copr_edit(copr, form, 'coprs_ns.copr_update')
411
412 413 @coprs_ns.route("/<username>/<coprname>/edit/") 414 @login_required 415 @req_with_copr 416 -def copr_edit(copr, form=None):
417 return render_copr_edit(copr, form, 'coprs_ns.copr_update')
418
419 420 -def _check_rpmfusion(repos):
421 if "rpmfusion" in repos: 422 message = flask.Markup('Using rpmfusion as dependency is nearly always wrong. Please see <a href="https://fedorahosted.org/copr/wiki/UserDocs#WhatIcanbuildinCopr">What I can build in Copr</a>.') 423 flask.flash(message, "error")
424
425 426 -def process_copr_update(copr, form):
427 copr.name = form.name.data 428 copr.homepage = form.homepage.data 429 copr.contact = form.contact.data 430 copr.repos = form.repos.data.replace("\n", " ") 431 copr.description = form.description.data 432 copr.instructions = form.instructions.data 433 copr.disable_createrepo = form.disable_createrepo.data 434 copr.build_enable_net = form.build_enable_net.data 435 copr.unlisted_on_hp = form.unlisted_on_hp.data 436 coprs_logic.CoprChrootsLogic.update_from_names( 437 flask.g.user, copr, form.selected_chroots) 438 try: 439 # form validation checks for duplicates 440 coprs_logic.CoprsLogic.update(flask.g.user, copr) 441 except (exceptions.ActionInProgressException, 442 exceptions.InsufficientRightsException) as e: 443 444 flask.flash(str(e), "error") 445 db.session.rollback() 446 else: 447 flask.flash("Project has been updated successfully.", "success") 448 db.session.commit() 449 _check_rpmfusion(copr.repos)
450 451 452 @coprs_ns.route("/g/<group_name>/<coprname>/update/", methods=["POST"])
453 @login_required 454 @req_with_copr 455 -def group_copr_update(copr):
456 form = forms.CoprFormFactory.create_form_cls(group=copr.group)() 457 458 if form.validate_on_submit(): 459 process_copr_update(copr, form) 460 return flask.redirect(url_for( 461 "coprs_ns.group_copr_detail", 462 group_name=copr.group.name, coprname=copr.name 463 )) 464 465 else: 466 return group_copr_edit(group_name=copr.group.name, coprname=copr.name, form=form)
467 468 469 @coprs_ns.route("/<username>/<coprname>/update/", methods=["POST"])
470 @login_required 471 @req_with_copr 472 -def copr_update(copr):
473 form = forms.CoprFormFactory.create_form_cls()() 474 475 if form.validate_on_submit(): 476 process_copr_update(copr, form) 477 return flask.redirect(url_for_copr_details(copr)) 478 else: 479 return render_copr_edit(copr, form, 'coprs_ns.copr_update')
480 481 482 @coprs_ns.route("/<username>/<coprname>/permissions_applier_change/", 483 methods=["POST"])
484 @login_required 485 @req_with_copr 486 -def copr_permissions_applier_change(copr):
487 permission = coprs_logic.CoprPermissionsLogic.get(copr, flask.g.user).first() 488 applier_permissions_form = \ 489 forms.PermissionsApplierFormFactory.create_form_cls(permission)() 490 491 if copr.user == flask.g.user: 492 flask.flash("Owner cannot request permissions for his own project.", "error") 493 elif applier_permissions_form.validate_on_submit(): 494 # we rely on these to be 0 or 1 from form. TODO: abstract from that 495 if permission is not None: 496 old_builder = permission.copr_builder 497 old_admin = permission.copr_admin 498 else: 499 old_builder = 0 500 old_admin = 0 501 new_builder = applier_permissions_form.copr_builder.data 502 new_admin = applier_permissions_form.copr_admin.data 503 coprs_logic.CoprPermissionsLogic.update_permissions_by_applier( 504 flask.g.user, copr, permission, new_builder, new_admin) 505 db.session.commit() 506 flask.flash( 507 "Successfuly updated permissions for project '{0}'." 508 .format(copr.name)) 509 admin_mails = [copr.user.mail] 510 for perm in copr.copr_permissions: 511 # this 2 means that his status (admin) is approved 512 if perm.copr_admin == 2: 513 admin_mails.append(perm.user.mail) 514 515 # sending emails 516 if flask.current_app.config.get("SEND_EMAILS", False): 517 for mail in admin_mails: 518 msg = MIMEText( 519 "{6} is asking for these permissions:\n\n" 520 "Builder: {0} -> {1}\nAdmin: {2} -> {3}\n\n" 521 "Project: {4}\nOwner: {5}".format( 522 helpers.PermissionEnum(old_builder), 523 helpers.PermissionEnum(new_builder), 524 helpers.PermissionEnum(old_admin), 525 helpers.PermissionEnum(new_admin), 526 copr.name, copr.user.name, flask.g.user.name)) 527 528 msg["Subject"] = "[Copr] {0}: {1} is asking permissons".format(copr.name, flask.g.user.name) 529 msg["From"] = "root@{0}".format(platform.node()) 530 msg["To"] = mail 531 s = smtplib.SMTP("localhost") 532 s.sendmail("root@{0}".format(platform.node()), mail, msg.as_string()) 533 s.quit() 534 535 return flask.redirect(flask.url_for("coprs_ns.copr_detail", 536 username=copr.user.name, 537 coprname=copr.name))
538 539 540 @coprs_ns.route("/<username>/<coprname>/update_permissions/", methods=["POST"])
541 @login_required 542 @req_with_copr 543 -def copr_update_permissions(copr):
544 permissions = copr.copr_permissions 545 permissions_form = forms.PermissionsFormFactory.create_form_cls( 546 permissions)() 547 548 if permissions_form.validate_on_submit(): 549 # we don't change owner (yet) 550 try: 551 # if admin is changing his permissions, his must be changed last 552 # so that we don't get InsufficientRightsException 553 permissions.sort( 554 key=lambda x: -1 if x.user_id == flask.g.user.id else 1) 555 for perm in permissions: 556 old_builder = perm.copr_builder 557 old_admin = perm.copr_admin 558 new_builder = permissions_form[ 559 "copr_builder_{0}".format(perm.user_id)].data 560 new_admin = permissions_form[ 561 "copr_admin_{0}".format(perm.user_id)].data 562 coprs_logic.CoprPermissionsLogic.update_permissions( 563 flask.g.user, copr, perm, new_builder, new_admin) 564 if flask.current_app.config.get("SEND_EMAILS", False) and \ 565 (old_builder is not new_builder or old_admin is not new_admin): 566 567 msg = MIMEText( 568 "Your permissions have changed:\n\n" 569 "Builder: {0} -> {1}\nAdmin: {2} -> {3}\n\n" 570 "Project: {4}\nOwner: {5}".format( 571 helpers.PermissionEnum(old_builder), 572 helpers.PermissionEnum(new_builder), 573 helpers.PermissionEnum(old_admin), 574 helpers.PermissionEnum(new_admin), 575 copr.name, copr.user.name)) 576 577 msg["Subject"] = "[Copr] {0}: Your permissions have changed".format(copr.name) 578 msg["From"] = "root@{0}".format(platform.node()) 579 msg["To"] = perm.user.mail 580 s = smtplib.SMTP("localhost") 581 s.sendmail("root@{0}".format(platform.node()), perm.user.mail, msg.as_string()) 582 s.quit() 583 # for now, we don't check for actions here, as permissions operation 584 # don't collide with any actions 585 except exceptions.InsufficientRightsException as e: 586 db.session.rollback() 587 flask.flash(str(e), "error") 588 else: 589 db.session.commit() 590 flask.flash("Project permissions were updated successfully.", "success") 591 592 return flask.redirect(url_for_copr_details(copr))
593 594 595 @coprs_ns.route("/id/<copr_id>/createrepo/", methods=["POST"])
596 @login_required 597 -def copr_createrepo(copr_id):
598 copr = ComplexLogic.get_copr_by_id_safe(copr_id) 599 600 chroots = [c.name for c in copr.active_chroots] 601 actions_logic.ActionsLogic.send_createrepo( 602 username=copr.owner_name, coprname=copr.name, 603 chroots=chroots) 604 605 db.session.commit() 606 flask.flash("Repository metadata will be regenerated in a few minutes ...") 607 return flask.redirect(url_for_copr_details(copr))
608
609 610 -def process_delete(copr, url_on_error, url_on_success):
611 form = forms.CoprDeleteForm() 612 if form.validate_on_submit(): 613 614 try: 615 ComplexLogic.delete_copr(copr) 616 except (exceptions.ActionInProgressException, 617 exceptions.InsufficientRightsException) as e: 618 619 db.session.rollback() 620 flask.flash(str(e), "error") 621 return flask.redirect(url_on_error) 622 else: 623 db.session.commit() 624 flask.flash("Project has been deleted successfully.") 625 return flask.redirect(url_on_success) 626 else: 627 return render_template("coprs/detail/settings/delete.html", form=form, copr=copr)
628 629 630 @coprs_ns.route("/<username>/<coprname>/delete/", methods=["GET", "POST"])
631 @login_required 632 @req_with_copr 633 -def copr_delete(copr):
634 return process_delete( 635 copr, 636 url_on_error=url_for("coprs_ns.copr_detail", 637 username=copr.user.name, coprname=copr.name), 638 url_on_success=url_for("coprs_ns.coprs_by_user", username=copr.user.username) 639 )
640 641 642 @coprs_ns.route("/g/<group_name>/<coprname>/delete/", methods=["GET", "POST"])
643 @login_required 644 @req_with_copr 645 -def group_copr_delete(copr):
646 647 return process_delete( 648 copr, 649 url_on_error=url_for('coprs_ns.group_copr_detail', 650 group_name=copr.group.name, coprname=copr.name), 651 url_on_success=url_for('groups_ns.list_projects_by_group', 652 group_name=copr.group.name) 653 )
654 655 656 @coprs_ns.route("/<username>/<coprname>/legal_flag/", methods=["POST"]) 662 663 664 @coprs_ns.route("/g/<group_name>/<coprname>/legal_flag/", methods=["POST"]) 670 702
703 704 @coprs_ns.route("/<username>/<coprname>/repo/<name_release>/", defaults={"repofile": None}) 705 @coprs_ns.route("/<username>/<coprname>/repo/<name_release>/<repofile>") 706 -def generate_repo_file(username, coprname, name_release, repofile):
707 """ Generate repo file for a given repo name. 708 Reponame = username-coprname """ 709 # This solution is used because flask splits off the last part after a 710 # dash, therefore user-re-po resolves to user-re/po instead of user/re-po 711 # FAS usernames may not contain dashes, so this construction is safe. 712 713 # support access to the group projects using @-notation 714 # todo: remove when yum/dnf plugin is updated to use new url schema 715 if username.startswith("@"): 716 return group_generate_repo_file(group_name=username[1:], coprname=coprname, 717 name_release=name_release, repofile=repofile) 718 719 copr = ComplexLogic.get_copr_safe(username, coprname) 720 return render_generate_repo_file(copr, name_release)
721
722 723 @coprs_ns.route("/g/<group_name>/<coprname>/repo/<name_release>/", defaults={"repofile": None}) 724 @coprs_ns.route("/g/<group_name>/<coprname>/repo/<name_release>/<repofile>") 725 @req_with_copr 726 -def group_generate_repo_file(copr, name_release, repofile):
727 """ Generate repo file for a given repo name. 728 Reponame = username-coprname """ 729 # This solution is used because flask splits off the last part after a 730 # dash, therefore user-re-po resolves to user-re/po instead of user/re-po 731 # FAS usernames may not contain dashes, so this construction is safe. 732 733 return render_generate_repo_file(copr, name_release)
734
735 736 -def render_generate_repo_file(copr, name_release):
737 738 # we need to check if we really got name release or it's a full chroot (caused by old dnf plugin) 739 if name_release in [c.name for c in copr.mock_chroots]: 740 chroot = [c for c in copr.mock_chroots if c.name == name_release][0] 741 kwargs = dict(coprname=copr.name, name_release=chroot.name_release) 742 if copr.is_a_group_project: 743 fixed_url = url_for("coprs_ns.group_generate_repo_file", 744 group_name=copr.group.name, **kwargs) 745 else: 746 fixed_url = url_for("coprs_ns.generate_repo_file", 747 username=copr.user.username, **kwargs) 748 return flask.redirect(fixed_url) 749 750 mock_chroot = coprs_logic.MockChrootsLogic.get_from_name(name_release, noarch=True).first() 751 if not mock_chroot: 752 raise ObjectNotFound("Chroot {} does not exist".format(name_release)) 753 754 url = os.path.join(copr.repo_url, '') # add trailing slash 755 repo_url = generate_repo_url(mock_chroot, url) 756 pubkey_url = urljoin(url, "pubkey.gpg") 757 response = flask.make_response( 758 flask.render_template("coprs/copr.repo", copr=copr, url=repo_url, pubkey_url=pubkey_url)) 759 response.mimetype = "text/plain" 760 response.headers["Content-Disposition"] = \ 761 "filename={0}.repo".format(copr.repo_name) 762 return response
763
764 765 @coprs_ns.route("/<username>/<coprname>/rpm/<name_release>/<rpmfile>") 766 -def copr_repo_rpm_file(username, coprname, name_release, rpmfile):
767 try: 768 packages_dir = os.path.join(app.config["DATA_DIR"], "repo-rpm-packages") 769 with open(os.path.join(packages_dir, rpmfile), "rb") as rpm: 770 response = flask.make_response(rpm.read()) 771 response.mimetype = "application/x-rpm" 772 response.headers["Content-Disposition"] = \ 773 "filename={0}".format(rpmfile) 774 return response 775 except IOError: 776 return flask.render_template("404.html")
777
778 779 -def render_monitor(copr, detailed=False):
780 monitor = builds_logic.BuildsMonitorLogic.get_monitor_data(copr) 781 oses = [chroot.os for chroot in copr.active_chroots_sorted] 782 oses_grouped = [(len(list(group)), key) for key, group in groupby(oses)] 783 archs = [chroot.arch for chroot in copr.active_chroots_sorted] 784 if detailed: 785 template = "coprs/detail/monitor/detailed.html" 786 else: 787 template = "coprs/detail/monitor/simple.html" 788 return flask.Response(stream_with_context(helpers.stream_template(template, 789 copr=copr, 790 monitor=monitor, 791 oses=oses_grouped, 792 archs=archs, 793 status_enum_func=helpers.StatusEnum)))
794
795 796 @coprs_ns.route("/<username>/<coprname>/monitor/") 797 @coprs_ns.route("/<username>/<coprname>/monitor/<detailed>") 798 @req_with_copr 799 -def copr_build_monitor(copr, detailed=False):
800 return render_monitor(copr, detailed == "detailed")
801
802 803 @coprs_ns.route("/g/<group_name>/<coprname>/monitor/") 804 @coprs_ns.route("/g/<group_name>/<coprname>/monitor/<detailed>") 805 @req_with_copr 806 -def group_copr_build_monitor(copr, detailed=False):
807 return render_monitor(copr, detailed == "detailed")
808
809 810 @coprs_ns.route("/<username>/<coprname>/fork/") 811 @coprs_ns.route("/g/<group_name>/<coprname>/fork/") 812 @login_required 813 @req_with_copr 814 -def copr_fork(copr):
815 form = forms.CoprForkFormFactory.create_form_cls(copr=copr, user=flask.g.user, groups=flask.g.user.user_groups)() 816 return render_copr_fork(copr, form)
817
818 819 -def render_copr_fork(copr, form, confirm=False):
820 return flask.render_template("coprs/fork.html", copr=copr, form=form, confirm=confirm)
821 822 823 @coprs_ns.route("/<username>/<coprname>/fork/", methods=["POST"]) 824 @coprs_ns.route("/g/<group_name>/<coprname>/fork/", methods=["POST"])
825 @login_required 826 @req_with_copr 827 -def copr_fork_post(copr):
828 form = forms.CoprForkFormFactory.create_form_cls(copr=copr, user=flask.g.user, groups=flask.g.user.user_groups)() 829 if form.validate_on_submit(): 830 dstgroup = ([g for g in flask.g.user.user_groups if g.at_name == form.owner.data] or [None])[0] 831 if flask.g.user.name != form.owner.data and not dstgroup: 832 return generic_error("There is no such group: {}".format(form.owner.data)) 833 834 fcopr, created = ComplexLogic.fork_copr(copr, flask.g.user, dstname=form.name.data, dstgroup=dstgroup) 835 if created: 836 msg = ("Forking project {} for you into {}. Please be aware that it may take a few minutes " 837 "to duplicate a backend data.".format(copr.full_name, fcopr.full_name)) 838 elif not created and form.confirm.data == True: 839 msg = ("Updating packages in {} from {}. Please be aware that it may take a few minutes " 840 "to duplicate a backend data.".format(copr.full_name, fcopr.full_name)) 841 else: 842 return render_copr_fork(copr, form, confirm=True) 843 844 db.session.commit() 845 flask.flash(msg) 846 847 return flask.redirect(url_for_copr_details(fcopr)) 848 return render_copr_fork(copr, form)
849 850 851 @coprs_ns.route("/update_search_index/", methods=["POST"])
852 -def copr_update_search_index():
853 subprocess.call(['/usr/share/copr/coprs_frontend/manage.py', 'update_indexes_quick', '1']) 854 return "OK"
855