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  import os 
  2  import time 
  3  import re 
  4   
  5  import flask 
  6  import platform 
  7  import smtplib 
  8  import sqlalchemy 
  9  from email.mime.text import MIMEText 
 10  from itertools import groupby 
 11   
 12  from coprs import app 
 13  from coprs import db 
 14  from coprs import exceptions 
 15  from coprs import forms 
 16  from coprs import helpers 
 17  from coprs import models 
 18   
 19  from coprs.views.misc import login_required, page_not_found 
 20   
 21  from coprs.views.coprs_ns import coprs_ns 
 22   
 23  from coprs.logic import builds_logic 
 24  from coprs.logic import coprs_logic 
 25  from coprs.helpers import parse_package_name, render_repo 
26 27 28 @coprs_ns.route("/", defaults={"page": 1}) 29 @coprs_ns.route("/<int:page>/") 30 -def coprs_show(page=1):
31 query = coprs_logic.CoprsLogic.get_multiple( 32 flask.g.user, with_mock_chroots=False) 33 paginator = helpers.Paginator(query, query.count(), page) 34 35 coprs = paginator.sliced_query 36 return flask.render_template("coprs/show.html", 37 coprs=coprs, 38 paginator=paginator)
39
40 41 @coprs_ns.route("/<username>/", defaults={"page": 1}) 42 @coprs_ns.route("/<username>/<int:page>/") 43 -def coprs_by_owner(username=None, page=1):
44 query = coprs_logic.CoprsLogic.get_multiple(flask.g.user, 45 user_relation="owned", 46 username=username, 47 with_mock_chroots=False) 48 49 paginator = helpers.Paginator(query, query.count(), page) 50 51 coprs = paginator.sliced_query 52 return flask.render_template("coprs/show.html", 53 coprs=coprs, 54 paginator=paginator)
55
56 57 @coprs_ns.route("/<username>/allowed/", defaults={"page": 1}) 58 @coprs_ns.route("/<username>/allowed/<int:page>/") 59 -def coprs_by_allowed(username=None, page=1):
60 query = coprs_logic.CoprsLogic.get_multiple(flask.g.user, 61 user_relation="allowed", 62 username=username, 63 with_mock_chroots=False) 64 paginator = helpers.Paginator(query, query.count(), page) 65 66 coprs = paginator.sliced_query 67 return flask.render_template("coprs/show.html", 68 coprs=coprs, 69 paginator=paginator)
70
71 72 @coprs_ns.route("/fulltext/", defaults={"page": 1}) 73 @coprs_ns.route("/fulltext/<int:page>/") 74 -def coprs_fulltext_search(page=1):
75 fulltext = flask.request.args.get("fulltext", "") 76 try: 77 query = coprs_logic.CoprsLogic.get_multiple_fulltext( 78 flask.g.user, fulltext) 79 except ValueError as e: 80 flask.flash(str(e)) 81 return flask.redirect(flask.request.referrer or 82 flask.url_for("coprs_ns.coprs_show")) 83 84 paginator = helpers.Paginator(query, query.count(), page) 85 86 coprs = paginator.sliced_query 87 return flask.render_template("coprs/show.html", 88 coprs=coprs, 89 paginator=paginator, 90 fulltext=fulltext)
91
92 93 @coprs_ns.route("/<username>/add/") 94 @login_required 95 -def copr_add(username):
96 form = forms.CoprFormFactory.create_form_cls()() 97 98 return flask.render_template("coprs/add.html", form=form)
99
100 101 @coprs_ns.route("/<username>/new/", methods=["POST"]) 102 @login_required 103 -def copr_new(username):
104 """ 105 Receive information from the user on how to create its new copr 106 and create it accordingly. 107 """ 108 109 form = forms.CoprFormFactory.create_form_cls()() 110 if form.validate_on_submit(): 111 copr = coprs_logic.CoprsLogic.add( 112 flask.g.user, 113 name=form.name.data, 114 repos=form.repos.data.replace("\n", " "), 115 selected_chroots=form.selected_chroots, 116 description=form.description.data, 117 instructions=form.instructions.data) 118 119 db.session.commit() 120 flask.flash("New project was successfully created.") 121 122 if form.initial_pkgs.data: 123 pkgs = form.initial_pkgs.data.replace("\n", " ").split(" ") 124 125 # validate (and skip bad) urls 126 bad_urls = [] 127 for pkg in pkgs: 128 if not re.match("^.*\.src\.rpm$", pkg): 129 bad_urls.append(pkg) 130 flask.flash("Bad url: {0} (skipped)".format(pkg)) 131 for bad_url in bad_urls: 132 pkgs.remove(bad_url) 133 134 if not pkgs: 135 flask.flash("No initial packages submitted") 136 else: 137 # build each package as a separate build 138 for pkg in pkgs: 139 builds_logic.BuildsLogic.add( 140 flask.g.user, 141 pkgs=pkg, 142 copr=copr) 143 144 db.session.commit() 145 flask.flash("Initial packages were successfully submitted " 146 "for building.") 147 148 return flask.redirect(flask.url_for("coprs_ns.copr_detail", 149 username=flask.g.user.name, 150 coprname=copr.name)) 151 else: 152 return flask.render_template("coprs/add.html", form=form)
153
154 155 @coprs_ns.route("/<username>/<coprname>/") 156 -def copr_detail(username, coprname):
157 query = coprs_logic.CoprsLogic.get( 158 flask.g.user, username, coprname, with_mock_chroots=True) 159 form = forms.CoprLegalFlagForm() 160 try: 161 copr = query.one() 162 except sqlalchemy.orm.exc.NoResultFound: 163 return page_not_found( 164 "Copr with name {0} does not exist.".format(coprname)) 165 166 return flask.render_template("coprs/detail/overview.html", 167 copr=copr, 168 form=form)
169
170 171 @coprs_ns.route("/<username>/<coprname>/permissions/") 172 -def copr_permissions(username, coprname):
173 query = coprs_logic.CoprsLogic.get(flask.g.user, username, coprname) 174 copr = query.first() 175 if not copr: 176 return page_not_found( 177 "Copr with name {0} does not exist.".format(coprname)) 178 179 permissions = coprs_logic.CoprPermissionsLogic.get_for_copr( 180 flask.g.user, copr).all() 181 if flask.g.user: 182 user_perm = flask.g.user.permissions_for_copr(copr) 183 else: 184 user_perm = None 185 186 permissions_applier_form = None 187 permissions_form = None 188 189 # generate a proper form for displaying 190 if flask.g.user: 191 if flask.g.user.can_edit(copr): 192 permissions_form = forms.PermissionsFormFactory.create_form_cls( 193 permissions)() 194 else: 195 # https://github.com/ajford/flask-wtf/issues/58 196 permissions_applier_form = \ 197 forms.PermissionsApplierFormFactory.create_form_cls( 198 user_perm)(formdata=None) 199 200 return flask.render_template( 201 "coprs/detail/permissions.html", 202 copr=copr, 203 permissions_form=permissions_form, 204 permissions_applier_form=permissions_applier_form, 205 permissions=permissions, 206 current_user_permissions=user_perm)
207
208 209 @coprs_ns.route("/<username>/<coprname>/edit/") 210 @login_required 211 -def copr_edit(username, coprname, form=None):
212 query = coprs_logic.CoprsLogic.get(flask.g.user, username, coprname) 213 copr = query.first() 214 215 if not copr: 216 return page_not_found( 217 "Copr with name {0} does not exist.".format(coprname)) 218 219 if not form: 220 form = forms.CoprFormFactory.create_form_cls( 221 copr.mock_chroots)(obj=copr) 222 223 return flask.render_template("coprs/detail/edit.html", 224 copr=copr, 225 form=form)
226
227 228 @coprs_ns.route("/<username>/<coprname>/update/", methods=["POST"]) 229 @login_required 230 -def copr_update(username, coprname):
231 copr = coprs_logic.CoprsLogic.get(flask.g.user, username, coprname).first() 232 form = forms.CoprFormFactory.create_form_cls(owner=copr.owner)() 233 234 if form.validate_on_submit(): 235 # we don"t change owner (yet) 236 copr.name = form.name.data 237 copr.repos = form.repos.data.replace("\n", " ") 238 copr.description = form.description.data 239 copr.instructions = form.instructions.data 240 coprs_logic.CoprChrootsLogic.update_from_names( 241 flask.g.user, copr, form.selected_chroots) 242 243 try: 244 # form validation checks for duplicates 245 coprs_logic.CoprsLogic.update( 246 flask.g.user, copr, check_for_duplicates=False) 247 except (exceptions.ActionInProgressException, 248 exceptions.InsufficientRightsException) as e: 249 250 flask.flash(str(e)) 251 db.session.rollback() 252 else: 253 flask.flash("Project was updated successfully.") 254 db.session.commit() 255 256 return flask.redirect(flask.url_for("coprs_ns.copr_detail", 257 username=username, 258 coprname=copr.name)) 259 else: 260 return copr_edit(username, coprname, form)
261 262 263 @coprs_ns.route("/<username>/<coprname>/permissions_applier_change/", 264 methods=["POST"])
265 @login_required 266 -def copr_permissions_applier_change(username, coprname):
267 copr = coprs_logic.CoprsLogic.get(flask.g.user, username, coprname).first() 268 permission = coprs_logic.CoprPermissionsLogic.get( 269 flask.g.user, copr, flask.g.user).first() 270 applier_permissions_form = \ 271 forms.PermissionsApplierFormFactory.create_form_cls(permission)() 272 273 if not copr: 274 return page_not_found( 275 "Project with name {0} does not exist.".format(coprname)) 276 277 if copr.owner == flask.g.user: 278 flask.flash("Owner cannot request permissions for his own project.") 279 elif applier_permissions_form.validate_on_submit(): 280 # we rely on these to be 0 or 1 from form. TODO: abstract from that 281 if permission is not None: 282 old_builder = permission.copr_builder 283 old_admin = permission.copr_admin 284 else: 285 old_builder = 0 286 old_admin = 0 287 new_builder = applier_permissions_form.copr_builder.data 288 new_admin = applier_permissions_form.copr_admin.data 289 coprs_logic.CoprPermissionsLogic.update_permissions_by_applier( 290 flask.g.user, copr, permission, new_builder, new_admin) 291 db.session.commit() 292 flask.flash( 293 "Successfuly updated permissions for project '{0}'." 294 .format(copr.name)) 295 admin_mails = [copr.owner.mail] 296 for perm in copr.copr_permissions: 297 # this 2 means that his status (admin) is approved 298 if perm.copr_admin == 2: 299 admin_mails.append(perm.user.mail) 300 301 # sending emails 302 if flask.current_app.config.get("SEND_EMAILS", False): 303 for mail in admin_mails: 304 msg = MIMEText("{6} is asking for these permissions:\n\n" 305 "Builder: {0} -> {1}\nAdmin: {2} -> {3}\n\n" 306 "Project: {4}\nOwner: {5}".format( 307 helpers.PermissionEnum(old_builder), 308 helpers.PermissionEnum(new_builder), 309 helpers.PermissionEnum(old_admin), 310 helpers.PermissionEnum(new_admin), 311 copr.name, copr.owner.name, flask.g.user.name), "plain") 312 msg["Subject"] = "[Copr] {0}: {1} is asking permissons".format(copr.name, flask.g.user.name) 313 msg["From"] = "root@{0}".format(platform.node()) 314 msg["To"] = mail 315 s = smtplib.SMTP("localhost") 316 s.sendmail("root@{0}".format(platform.node()), mail, msg.as_string()) 317 s.quit() 318 319 320 return flask.redirect(flask.url_for("coprs_ns.copr_detail", 321 username=copr.owner.name, 322 coprname=copr.name))
323
324 325 @coprs_ns.route("/<username>/<coprname>/update_permissions/", methods=["POST"]) 326 @login_required 327 -def copr_update_permissions(username, coprname):
328 query = coprs_logic.CoprsLogic.get(flask.g.user, username, coprname) 329 copr = query.first() 330 permissions = copr.copr_permissions 331 permissions_form = forms.PermissionsFormFactory.create_form_cls( 332 permissions)() 333 334 if permissions_form.validate_on_submit(): 335 # we don't change owner (yet) 336 try: 337 # if admin is changing his permissions, his must be changed last 338 # so that we don't get InsufficientRightsException 339 permissions.sort( 340 cmp=lambda x, y: -1 if y.user_id == flask.g.user.id else 1) 341 for perm in permissions: 342 old_builder = perm.copr_builder 343 old_admin = perm.copr_admin 344 new_builder = permissions_form[ 345 "copr_builder_{0}".format(perm.user_id)].data 346 new_admin = permissions_form[ 347 "copr_admin_{0}".format(perm.user_id)].data 348 coprs_logic.CoprPermissionsLogic.update_permissions( 349 flask.g.user, copr, perm, new_builder, new_admin) 350 if flask.current_app.config.get("SEND_EMAILS", False): 351 if old_builder is not new_builder or \ 352 old_admin is not new_admin: 353 msg = MIMEText("Your permissions have changed:\n\n" 354 "Builder: {0} -> {1}\nAdmin: {2} -> {3}\n\n" 355 "Project: {4}\nOwner: {5}".format( 356 helpers.PermissionEnum(old_builder), 357 helpers.PermissionEnum(new_builder), 358 helpers.PermissionEnum(old_admin), 359 helpers.PermissionEnum(new_admin), 360 copr.name, copr.owner.name), "plain") 361 msg["Subject"] = "[Copr] {0}: Your permissions have changed".format(copr.name) 362 msg["From"] = "root@{0}".format(platform.node()) 363 msg["To"] = perm.user.mail 364 s = smtplib.SMTP("localhost") 365 s.sendmail("root@{0}".format(platform.node()), perm.user.mail, msg.as_string()) 366 s.quit() 367 368 # for now, we don't check for actions here, as permissions operation 369 # don't collide with any actions 370 except exceptions.InsufficientRightsException as e: 371 db.session.rollback() 372 flask.flash(str(e)) 373 else: 374 db.session.commit() 375 flask.flash("Project permissions were updated successfully.") 376 377 return flask.redirect(flask.url_for("coprs_ns.copr_detail", 378 username=copr.owner.name, 379 coprname=copr.name))
380
381 382 @coprs_ns.route("/<username>/<coprname>/delete/", methods=["GET", "POST"]) 383 @login_required 384 -def copr_delete(username, coprname):
385 form = forms.CoprDeleteForm() 386 copr = coprs_logic.CoprsLogic.get(flask.g.user, username, coprname).first() 387 388 if form.validate_on_submit() and copr: 389 builds_query = builds_logic.BuildsLogic.get_multiple( 390 flask.g.user, copr=copr) 391 try: 392 for build in builds_query: 393 builds_logic.BuildsLogic.delete_build(flask.g.user, build) 394 coprs_logic.CoprsLogic.delete(flask.g.user, copr) 395 except (exceptions.ActionInProgressException, 396 exceptions.InsufficientRightsException) as e: 397 398 db.session.rollback() 399 flask.flash(str(e)) 400 return flask.redirect(flask.url_for("coprs_ns.copr_detail", 401 username=username, 402 coprname=coprname)) 403 else: 404 db.session.commit() 405 flask.flash("Project was deleted successfully.") 406 return flask.redirect(flask.url_for("coprs_ns.coprs_by_owner", 407 username=username)) 408 else: 409 if copr: 410 return flask.render_template("coprs/detail/delete.html", 411 form=form, copr=copr) 412 else: 413 return page_not_found("Project {0}/{1} does not exist" 414 .format(username, coprname))
415 461
462 463 @coprs_ns.route("/<username>/<coprname>/repo/<chroot>/", defaults={"repofile": None}) 464 @coprs_ns.route("/<username>/<coprname>/repo/<chroot>/<repofile>") 465 -def generate_repo_file(username, coprname, chroot, repofile):
466 """ Generate repo file for a given repo name. 467 Reponame = username-coprname """ 468 # This solution is used because flask splits off the last part after a 469 # dash, therefore user-re-po resolves to user-re/po instead of user/re-po 470 # FAS usernames may not contain dashes, so this construction is safe. 471 472 reponame = "{0}-{1}".format(username, coprname) 473 474 if repofile is not None and repofile != username + '-' + coprname + '-' + chroot + '.repo': 475 return page_not_found( 476 "Repository filename does not match expected: {0}" 477 .format(repofile)) 478 479 480 copr = None 481 try: 482 # query.one() is used since it fetches all builds, unlike 483 # query.first(). 484 copr = coprs_logic.CoprsLogic.get(flask.g.user, username, coprname, 485 with_builds=True).one() 486 except sqlalchemy.orm.exc.NoResultFound: 487 return page_not_found( 488 "Project {0}/{1} does not exist".format(username, coprname)) 489 490 mock_chroot = coprs_logic.MockChrootsLogic.get_from_name(chroot, 491 noarch=True).first() 492 if not mock_chroot: 493 return page_not_found("Chroot {0} does not exist".format(chroot)) 494 495 url = "" 496 for build in copr.builds: 497 if build.results: 498 url = build.results 499 break 500 501 if not url: 502 return page_not_found( 503 "Repository not initialized: No finished builds in {0}/{1}." 504 .format(username, coprname)) 505 506 response = flask.make_response(render_repo(copr, mock_chroot, url)) 507 response.mimetype = "text/plain" 508 response.headers["Content-Disposition"] = "filename={0}.repo".format( 509 reponame) 510 511 return response
512
513 514 @coprs_ns.route("/<username>/<coprname>/monitor/") 515 -def copr_build_monitor(username, coprname):
516 query = coprs_logic.CoprsLogic.get( 517 flask.g.user, username, coprname, with_mock_chroots=True) 518 form = forms.CoprLegalFlagForm() 519 try: 520 copr = query.one() 521 except sqlalchemy.orm.exc.NoResultFound: 522 return page_not_found( 523 "Copr with name {0} does not exist.".format(coprname)) 524 525 builds_query = builds_logic.BuildsLogic.get_multiple( 526 flask.g.user, copr=copr) 527 builds = builds_query.order_by("-id").all() 528 529 # please don"t waste time trying to decipher this 530 # the only reason why this is necessary is non-existent 531 # database design 532 # 533 # loop goes through builds trying to approximate 534 # per-package results based on previous builds 535 # - it can"t determine build results if build contains 536 # more than one package as this data is not available 537 538 packages = [] 539 build = None 540 chroots = set([chroot.name for chroot in copr.active_chroots]) 541 oses = [chroot.os for chroot in copr.active_chroots] 542 oses_grouped = [(len(list(group)), key) for key, group in groupby(oses)] 543 archs = [chroot.arch for chroot in copr.active_chroots] 544 latest_build = None 545 546 if builds: 547 latest_build = builds[0] 548 chroots.union([chroot.name for chroot in latest_build.build_chroots]) 549 550 chroots = sorted(chroots) 551 552 out = [] 553 for build in builds: 554 chroot_results = {chroot.name: chroot.state 555 for chroot in build.build_chroots} 556 557 build_results = [] 558 for chroot_name in chroots: 559 if chroot_name in chroot_results: 560 build_results.append((build.id, chroot_results[chroot_name])) 561 else: 562 build_results.append((build.id, None)) 563 564 for pkg_url in build.pkgs.split(): 565 pkg = os.path.basename(pkg_url) 566 pkg_name = parse_package_name(pkg) 567 568 if pkg_name in out: 569 continue 570 571 packages.append((pkg_name, build.pkg_version, build_results)) 572 out.append(pkg_name) 573 packages.sort() 574 575 return flask.render_template("coprs/detail/monitor.html", 576 copr=copr, 577 build=latest_build, 578 chroots=chroots, oses=oses_grouped, archs=archs, 579 packages=packages, 580 form=form)
581