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