1
2
3 import os
4 import time
5 import fnmatch
6 import uuid
7 import subprocess
8 from six.moves.urllib.parse import urljoin
9
10 import flask
11 from flask import render_template, url_for, stream_with_context
12 import platform
13 import smtplib
14 import tempfile
15 import sqlalchemy
16 import modulemd
17 from email.mime.text import MIMEText
18 from itertools import groupby
19 from wtforms import ValidationError
20
21 from pygments import highlight
22 from pygments.lexers import get_lexer_by_name
23 from pygments.formatters import HtmlFormatter
24
25 from coprs import app
26 from coprs import db
27 from coprs import rcp
28 from coprs import exceptions
29 from coprs import forms
30 from coprs import helpers
31 from coprs import models
32 from coprs.exceptions import ObjectNotFound
33 from coprs.logic.coprs_logic import CoprsLogic
34 from coprs.logic.packages_logic import PackagesLogic
35 from coprs.logic.stat_logic import CounterStatLogic
36 from coprs.logic.users_logic import UsersLogic
37 from coprs.logic.modules_logic import ModulesLogic, ModulemdGenerator, ModuleBuildFacade
38 from coprs.rmodels import TimedStatEvents
39
40 from coprs.logic.complex_logic import ComplexLogic
41
42 from coprs.views.misc import login_required, page_not_found, req_with_copr, req_with_copr, generic_error
43
44 from coprs.views.coprs_ns import coprs_ns
45 from coprs.views.groups_ns import groups_ns
46
47 from coprs.logic import builds_logic, coprs_logic, actions_logic, users_logic
48 from coprs.helpers import parse_package_name, generate_repo_url, CHROOT_RPMS_DL_STAT_FMT, CHROOT_REPO_MD_DL_STAT_FMT, \
49 str2bool, url_for_copr_view, REPO_DL_STAT_FMT, CounterStatType
56
63
64
65 @coprs_ns.route("/", defaults={"page": 1})
66 @coprs_ns.route("/<int:page>/")
67 -def coprs_show(page=1):
88
89
90 @coprs_ns.route("/<username>/", defaults={"page": 1})
91 @coprs_ns.route("/<username>/<int:page>/")
92 -def coprs_by_user(username=None, page=1):
93 user = users_logic.UsersLogic.get(username).first()
94 if not user:
95 return page_not_found(
96 "User {0} does not exist.".format(username))
97
98 query = CoprsLogic.get_multiple_owned_by_username(username)
99 query = CoprsLogic.filter_without_group_projects(query)
100 query = CoprsLogic.set_query_order(query, desc=True)
101
102 paginator = helpers.Paginator(query, query.count(), page)
103
104 coprs = paginator.sliced_query
105
106
107 users_builds = builds_logic.BuildsLogic.get_recent_tasks(flask.g.user, 4)
108
109 data = builds_logic.BuildsLogic.get_tasks_from_last_day()
110
111 return flask.render_template("coprs/show/user.html",
112 user=user,
113 coprs=coprs,
114 paginator=paginator,
115 tasks_info=ComplexLogic.get_queue_sizes(),
116 users_builds=users_builds,
117 graph=data)
118
119
120 @coprs_ns.route("/fulltext/", defaults={"page": 1})
121 @coprs_ns.route("/fulltext/<int:page>/")
122 -def coprs_fulltext_search(page=1):
123 fulltext = flask.request.args.get("fulltext", "")
124 try:
125 query = coprs_logic.CoprsLogic.get_multiple_fulltext(fulltext)
126 except ValueError as e:
127 flask.flash(str(e), "error")
128 return flask.redirect(flask.request.referrer or
129 flask.url_for("coprs_ns.coprs_show"))
130
131 paginator = helpers.Paginator(query, query.count(), page,
132 additional_params={"fulltext": fulltext})
133
134 data = builds_logic.BuildsLogic.get_tasks_from_last_day()
135
136 coprs = paginator.sliced_query
137 return render_template("coprs/show/fulltext.html",
138 coprs=coprs,
139 paginator=paginator,
140 fulltext=fulltext,
141 tasks_info=ComplexLogic.get_queue_sizes(),
142 graph=data)
143
144
145 @coprs_ns.route("/<username>/add/")
146 @login_required
147 -def copr_add(username):
151
152
153 @coprs_ns.route("/g/<group_name>/add/")
154 @login_required
155 -def group_copr_add(group_name):
161
162
163 @coprs_ns.route("/g/<group_name>/new/", methods=["POST"])
164 @login_required
165 -def group_copr_new(group_name):
166 group = ComplexLogic.get_group_by_name_safe(group_name)
167 form = forms.CoprFormFactory.create_form_cls(group=group)()
168
169 if form.validate_on_submit():
170 try:
171 copr = coprs_logic.CoprsLogic.add(
172 flask.g.user,
173 name=form.name.data,
174 homepage=form.homepage.data,
175 contact=form.contact.data,
176 repos=form.repos.data.replace("\n", " "),
177 selected_chroots=form.selected_chroots,
178 description=form.description.data,
179 instructions=form.instructions.data,
180 disable_createrepo=form.disable_createrepo.data,
181 build_enable_net=form.build_enable_net.data,
182 unlisted_on_hp=form.unlisted_on_hp.data,
183 group=group,
184 persistent=form.persistent.data,
185 auto_prune=(form.auto_prune.data if flask.g.user.admin else True),
186 use_bootstrap_container=form.use_bootstrap_container.data,
187 follow_fedora_branching=form.follow_fedora_branching.data,
188 )
189 except (exceptions.DuplicateException, exceptions.NonAdminCannotCreatePersistentProject) as e:
190 flask.flash(str(e), "error")
191 return flask.render_template("coprs/group_add.html", form=form, group=group)
192
193 db.session.add(copr)
194 db.session.commit()
195 after_the_project_creation(copr, form)
196
197 return flask.redirect(url_for_copr_details(copr))
198 else:
199 return flask.render_template("coprs/group_add.html", form=form, group=group)
200
201
202 @coprs_ns.route("/<username>/new/", methods=["POST"])
203 @login_required
204 -def copr_new(username):
205 """
206 Receive information from the user on how to create its new copr
207 and create it accordingly.
208 """
209
210 form = forms.CoprFormFactory.create_form_cls()()
211 if form.validate_on_submit():
212 try:
213 copr = coprs_logic.CoprsLogic.add(
214 flask.g.user,
215 name=form.name.data,
216 homepage=form.homepage.data,
217 contact=form.contact.data,
218 repos=form.repos.data.replace("\n", " "),
219 selected_chroots=form.selected_chroots,
220 description=form.description.data,
221 instructions=form.instructions.data,
222 disable_createrepo=form.disable_createrepo.data,
223 build_enable_net=form.build_enable_net.data,
224 unlisted_on_hp=form.unlisted_on_hp.data,
225 persistent=form.persistent.data,
226 auto_prune=(form.auto_prune.data if flask.g.user.admin else True),
227 use_bootstrap_container=form.use_bootstrap_container.data,
228 follow_fedora_branching=form.follow_fedora_branching.data,
229 )
230 except (exceptions.DuplicateException, exceptions.NonAdminCannotCreatePersistentProject) as e:
231 flask.flash(str(e), "error")
232 return flask.render_template("coprs/add.html", form=form)
233
234 db.session.commit()
235 after_the_project_creation(copr, form)
236
237 return flask.redirect(url_for_copr_details(copr))
238 else:
239 return flask.render_template("coprs/add.html", form=form)
240
243 flask.flash("New project has been created successfully.", "success")
244 _check_rpmfusion(copr.repos)
245 if form.initial_pkgs.data:
246 pkgs = form.initial_pkgs.data.replace("\n", " ").split(" ")
247
248
249 bad_urls = []
250 for pkg in pkgs:
251 if not pkg.endswith(".src.rpm"):
252 bad_urls.append(pkg)
253 flask.flash("Bad url: {0} (skipped)".format(pkg))
254 for bad_url in bad_urls:
255 pkgs.remove(bad_url)
256
257 if not pkgs:
258 flask.flash("No initial packages submitted")
259 else:
260
261 for pkg in pkgs:
262 builds_logic.BuildsLogic.add(
263 flask.g.user,
264 pkgs=pkg,
265 srpm_url=pkg,
266 copr=copr,
267 enable_net=form.build_enable_net.data
268 )
269
270 db.session.commit()
271 flask.flash("Initial packages were successfully submitted "
272 "for building.")
273
274
275 @coprs_ns.route("/<username>/<coprname>/report-abuse")
276 @req_with_copr
277 @login_required
278 -def copr_report_abuse(copr):
280
281
282 @coprs_ns.route("/g/<group_name>/<coprname>/report-abuse")
283 @req_with_copr
284 @login_required
285 -def group_copr_report_abuse(copr):
287
292
293
294 @coprs_ns.route("/g/<group_name>/<coprname>/")
295 @req_with_copr
296 -def group_copr_detail(copr):
298
299
300 @coprs_ns.route("/<username>/<coprname>/")
301 @req_with_copr
302 -def copr_detail(copr):
306
309 repo_dl_stat = CounterStatLogic.get_copr_repo_dl_stat(copr)
310 form = forms.CoprLegalFlagForm()
311 repos_info = {}
312 for chroot in copr.active_chroots:
313
314
315
316
317
318 chroot_rpms_dl_stat_key = CHROOT_RPMS_DL_STAT_FMT.format(
319 copr_user=copr.user.name,
320 copr_project_name=copr.name,
321 copr_chroot=chroot.name,
322 )
323 chroot_rpms_dl_stat = TimedStatEvents.get_count(
324 rconnect=rcp.get_connection(),
325 name=chroot_rpms_dl_stat_key,
326 )
327
328 logoset = set()
329 logodir = app.static_folder + "/chroot_logodir"
330 for logo in os.listdir(logodir):
331
332 if fnmatch.fnmatch(logo, "*.png"):
333 logoset.add(logo.strip(".png"))
334
335 if chroot.name_release not in repos_info:
336 logo = None
337 if chroot.name_release in logoset:
338 logo = chroot.name_release + ".png"
339 elif chroot.os_release in logoset:
340 logo = chroot.os_release + ".png"
341
342 repos_info[chroot.name_release] = {
343 "name_release": chroot.name_release,
344 "name_release_human": chroot.name_release_human,
345 "os_release": chroot.os_release,
346 "os_version": chroot.os_version,
347 "logo": logo,
348 "arch_list": [chroot.arch],
349 "repo_file": "{}-{}.repo".format(copr.repo_id, chroot.name_release),
350 "dl_stat": repo_dl_stat[chroot.name_release],
351 "rpm_dl_stat": {
352 chroot.arch: chroot_rpms_dl_stat
353 }
354 }
355 else:
356 repos_info[chroot.name_release]["arch_list"].append(chroot.arch)
357 repos_info[chroot.name_release]["rpm_dl_stat"][chroot.arch] = chroot_rpms_dl_stat
358 repos_info_list = sorted(repos_info.values(), key=lambda rec: rec["name_release"])
359 builds = builds_logic.BuildsLogic.get_multiple_by_copr(copr=copr).limit(1).all()
360
361 return flask.render_template(
362 "coprs/detail/overview.html",
363 copr=copr,
364 user=flask.g.user,
365 form=form,
366 repo_dl_stat=repo_dl_stat,
367 repos_info_list=repos_info_list,
368 latest_build=builds[0] if len(builds) == 1 else None,
369 )
370
371
372 @coprs_ns.route("/<username>/<coprname>/permissions/")
373 @req_with_copr
374 -def copr_permissions(copr):
402
405 if not copr.webhook_secret:
406 copr.webhook_secret = str(uuid.uuid4())
407 db.session.add(copr)
408 db.session.commit()
409
410 bitbucket_url = "https://{}/webhooks/bitbucket/{}/{}/".format(
411 app.config["PUBLIC_COPR_HOSTNAME"],
412 copr.id,
413 copr.webhook_secret)
414
415 github_url = "https://{}/webhooks/github/{}/{}/".format(
416 app.config["PUBLIC_COPR_HOSTNAME"],
417 copr.id,
418 copr.webhook_secret)
419
420 gitlab_url = "https://{}/webhooks/gitlab/{}/{}/".format(
421 app.config["PUBLIC_COPR_HOSTNAME"],
422 copr.id,
423 copr.webhook_secret)
424
425 custom_url = "https://{}/webhooks/custom/{}/{}/".format(
426 app.config["PUBLIC_COPR_HOSTNAME"],
427 copr.id,
428 copr.webhook_secret) + "<PACKAGE_NAME>/"
429
430 return flask.render_template(
431 "coprs/detail/settings/webhooks.html",
432 copr=copr, bitbucket_url=bitbucket_url, github_url=github_url,
433 gitlab_url=gitlab_url, custom_url=custom_url)
434
435
436 @coprs_ns.route("/g/<group_name>/<coprname>/webhooks/")
437 @login_required
438 @req_with_copr
439 -def group_copr_webhooks(copr):
441
442
443 @coprs_ns.route("/<username>/<coprname>/webhooks/")
444 @login_required
445 @req_with_copr
446 -def copr_webhooks(copr):
448
457
458
459 @coprs_ns.route("/g/<group_name>/<coprname>/edit/")
460 @login_required
461 @req_with_copr
462 -def group_copr_edit(copr, form=None):
464
465
466 @coprs_ns.route("/<username>/<coprname>/edit/")
467 @login_required
468 @req_with_copr
469 -def copr_edit(copr, form=None):
471
474 if "rpmfusion" in repos:
475 message = flask.Markup('Using rpmfusion as dependency is nearly always wrong. Please see <a href="https://docs.pagure.org/copr.copr/user_documentation.html#what-i-can-build-in-copr">What I can build in Copr</a>.')
476 flask.flash(message, "error")
477
509
510
511 @coprs_ns.route("/g/<group_name>/<coprname>/update/", methods=["POST"])
512 @login_required
513 @req_with_copr
514 -def group_copr_update(copr):
526
527
528 @coprs_ns.route("/<username>/<coprname>/update/", methods=["POST"])
529 @login_required
530 @req_with_copr
531 -def copr_update(copr):
539
540
541 @coprs_ns.route("/<username>/<coprname>/permissions_applier_change/",
542 methods=["POST"])
546 permission = coprs_logic.CoprPermissionsLogic.get(copr, flask.g.user).first()
547 applier_permissions_form = \
548 forms.PermissionsApplierFormFactory.create_form_cls(permission)()
549
550 if copr.user == flask.g.user:
551 flask.flash("Owner cannot request permissions for his own project.", "error")
552 elif applier_permissions_form.validate_on_submit():
553
554 if permission is not None:
555 old_builder = permission.copr_builder
556 old_admin = permission.copr_admin
557 else:
558 old_builder = 0
559 old_admin = 0
560 new_builder = applier_permissions_form.copr_builder.data
561 new_admin = applier_permissions_form.copr_admin.data
562 coprs_logic.CoprPermissionsLogic.update_permissions_by_applier(
563 flask.g.user, copr, permission, new_builder, new_admin)
564 db.session.commit()
565 flask.flash(
566 "Successfully updated permissions for project '{0}'."
567 .format(copr.name))
568 admin_mails = [copr.user.mail]
569 for perm in copr.copr_permissions:
570
571 if perm.copr_admin == 2:
572 admin_mails.append(perm.user.mail)
573
574
575 if flask.current_app.config.get("SEND_EMAILS", False):
576 for mail in admin_mails:
577 msg = MIMEText(
578 "{6} is asking for these permissions:\n\n"
579 "Builder: {0} -> {1}\nAdmin: {2} -> {3}\n\n"
580 "Project: {4}\nOwner: {5}".format(
581 helpers.PermissionEnum(old_builder),
582 helpers.PermissionEnum(new_builder),
583 helpers.PermissionEnum(old_admin),
584 helpers.PermissionEnum(new_admin),
585 copr.name, copr.user.name, flask.g.user.name))
586
587 msg["Subject"] = "[Copr] {0}: {1} is asking permissions".format(copr.name, flask.g.user.name)
588 msg["From"] = "root@{0}".format(platform.node())
589 msg["To"] = mail
590 s = smtplib.SMTP("localhost")
591 s.sendmail("root@{0}".format(platform.node()), mail, msg.as_string())
592 s.quit()
593
594 return flask.redirect(flask.url_for("coprs_ns.copr_detail",
595 username=copr.user.name,
596 coprname=copr.name))
597
598
599 @coprs_ns.route("/<username>/<coprname>/update_permissions/", methods=["POST"])
600 @login_required
601 @req_with_copr
602 -def copr_update_permissions(copr):
603 permissions = copr.copr_permissions
604 permissions_form = forms.PermissionsFormFactory.create_form_cls(
605 permissions)()
606
607 if permissions_form.validate_on_submit():
608
609 try:
610
611
612 permissions.sort(
613 key=lambda x: -1 if x.user_id == flask.g.user.id else 1)
614 for perm in permissions:
615 old_builder = perm.copr_builder
616 old_admin = perm.copr_admin
617 new_builder = permissions_form[
618 "copr_builder_{0}".format(perm.user_id)].data
619 new_admin = permissions_form[
620 "copr_admin_{0}".format(perm.user_id)].data
621 coprs_logic.CoprPermissionsLogic.update_permissions(
622 flask.g.user, copr, perm, new_builder, new_admin)
623 if flask.current_app.config.get("SEND_EMAILS", False) and \
624 (old_builder is not new_builder or old_admin is not new_admin):
625
626 msg = MIMEText(
627 "Your permissions have changed:\n\n"
628 "Builder: {0} -> {1}\nAdmin: {2} -> {3}\n\n"
629 "Project: {4}\nOwner: {5}".format(
630 helpers.PermissionEnum(old_builder),
631 helpers.PermissionEnum(new_builder),
632 helpers.PermissionEnum(old_admin),
633 helpers.PermissionEnum(new_admin),
634 copr.name, copr.user.name))
635
636 msg["Subject"] = "[Copr] {0}: Your permissions have changed".format(copr.name)
637 msg["From"] = "root@{0}".format(platform.node())
638 msg["To"] = perm.user.mail
639 s = smtplib.SMTP("localhost")
640 s.sendmail("root@{0}".format(platform.node()), perm.user.mail, msg.as_string())
641 s.quit()
642
643
644 except exceptions.InsufficientRightsException as e:
645 db.session.rollback()
646 flask.flash(str(e), "error")
647 else:
648 db.session.commit()
649 flask.flash("Project permissions were updated successfully.", "success")
650
651 return flask.redirect(url_for_copr_details(copr))
652
653
654 @coprs_ns.route("/id/<copr_id>/createrepo/", methods=["POST"])
655 @login_required
656 -def copr_createrepo(copr_id):
671
674 form = forms.CoprDeleteForm()
675 if form.validate_on_submit():
676
677 try:
678 ComplexLogic.delete_copr(copr)
679 except (exceptions.ActionInProgressException,
680 exceptions.InsufficientRightsException) as e:
681
682 db.session.rollback()
683 flask.flash(str(e), "error")
684 return flask.redirect(url_on_error)
685 else:
686 db.session.commit()
687 flask.flash("Project has been deleted successfully.")
688 return flask.redirect(url_on_success)
689 else:
690 return render_template("coprs/detail/settings/delete.html", form=form, copr=copr)
691
692
693 @coprs_ns.route("/<username>/<coprname>/delete/", methods=["GET", "POST"])
694 @login_required
695 @req_with_copr
696 -def copr_delete(copr):
703
704
705 @coprs_ns.route("/g/<group_name>/<coprname>/delete/", methods=["GET", "POST"])
706 @login_required
707 @req_with_copr
708 -def group_copr_delete(copr):
717
718
719 @coprs_ns.route("/<username>/<coprname>/legal_flag/", methods=["POST"])
720 @login_required
721 @req_with_copr
722 -def copr_legal_flag(copr):
725
726
727 @coprs_ns.route("/g/<group_name>/<coprname>/legal_flag/", methods=["POST"])
728 @login_required
729 @req_with_copr
730 -def group_copr_legal_flag(copr):
733
736 form = forms.CoprLegalFlagForm()
737 legal_flag = models.LegalFlag(raise_message=form.comment.data,
738 raised_on=int(time.time()),
739 copr=copr,
740 reporter=flask.g.user)
741 db.session.add(legal_flag)
742 db.session.commit()
743 send_to = app.config["SEND_LEGAL_TO"] or ["root@localhost"]
744 hostname = platform.node()
745 navigate_to = "\nNavigate to http://{0}{1}".format(
746 hostname, flask.url_for("admin_ns.legal_flag"))
747 contact = "\nContact on owner is: {}".format(contact_info)
748 reported_by = "\nReported by {0} <{1}>".format(flask.g.user.name,
749 flask.g.user.mail)
750 try:
751 msg = MIMEText(
752 form.comment.data + navigate_to + contact + reported_by, "plain")
753 except UnicodeEncodeError:
754 msg = MIMEText(form.comment.data.encode(
755 "utf-8") + navigate_to + contact + reported_by, "plain", "utf-8")
756 msg["Subject"] = "Legal flag raised on {0}".format(copr.name)
757 msg["From"] = "root@{0}".format(hostname)
758 msg["To"] = ", ".join(send_to)
759 s = smtplib.SMTP("localhost")
760 s.sendmail("root@{0}".format(hostname), send_to, msg.as_string())
761 s.quit()
762 flask.flash("Admin has been noticed about your report"
763 " and will investigate the project shortly.")
764 return flask.redirect(url_for_copr_details(copr))
765
766
767 @coprs_ns.route("/<username>/<coprname>/repo/<name_release>/", defaults={"repofile": None})
768 @coprs_ns.route("/<username>/<coprname>/repo/<name_release>/<repofile>")
769 -def generate_repo_file(username, coprname, name_release, repofile):
784
785
786 @coprs_ns.route("/g/<group_name>/<coprname>/repo/<name_release>/", defaults={"repofile": None})
787 @coprs_ns.route("/g/<group_name>/<coprname>/repo/<name_release>/<repofile>")
788 @req_with_copr
789 -def group_generate_repo_file(copr, name_release, repofile):
797
800
801
802 if name_release in [c.name for c in copr.mock_chroots]:
803 chroot = [c for c in copr.mock_chroots if c.name == name_release][0]
804 kwargs = dict(coprname=copr.name, name_release=chroot.name_release)
805 if copr.is_a_group_project:
806 fixed_url = url_for("coprs_ns.group_generate_repo_file",
807 group_name=copr.group.name, **kwargs)
808 else:
809 fixed_url = url_for("coprs_ns.generate_repo_file",
810 username=copr.user.username, **kwargs)
811 return flask.redirect(fixed_url)
812
813 mock_chroot = coprs_logic.MockChrootsLogic.get_from_name(name_release, noarch=True).first()
814 if not mock_chroot:
815 raise ObjectNotFound("Chroot {} does not exist".format(name_release))
816
817 url = os.path.join(copr.repo_url, '')
818 repo_url = generate_repo_url(mock_chroot, url)
819 pubkey_url = urljoin(url, "pubkey.gpg")
820 response = flask.make_response(
821 flask.render_template("coprs/copr.repo", copr=copr, url=repo_url, pubkey_url=pubkey_url))
822 response.mimetype = "text/plain"
823 response.headers["Content-Disposition"] = \
824 "filename={0}.repo".format(copr.repo_name)
825
826 name = REPO_DL_STAT_FMT.format(**{
827 'copr_user': copr.user.name,
828 'copr_project_name': copr.name,
829 'copr_name_release': name_release,
830 })
831 CounterStatLogic.incr(name=name, counter_type=CounterStatType.REPO_DL)
832 db.session.commit()
833
834 return response
835
836
837
838
839
840
841 @coprs_ns.route("/<username>/<coprname>/module_repo/<name_release>/<module_nsv>.repo")
842 @coprs_ns.route("/g/<group_name>/<coprname>/module_repo/<name_release>/<module_nsv>.repo")
843 @req_with_copr
844 -def generate_module_repo_file(copr, name_release, module_nsv):
847
849 module = ModulesLogic.get_by_nsv_str(copr, module_nsv).one()
850 mock_chroot = coprs_logic.MockChrootsLogic.get_from_name(name_release, noarch=True).first()
851 url = os.path.join(copr.repo_url, '')
852 repo_url = generate_repo_url(mock_chroot, copr.modules_url)
853 baseurl = "{}+{}/latest/$basearch".format(repo_url.rstrip("/"), module_nsv)
854 pubkey_url = urljoin(url, "pubkey.gpg")
855 response = flask.make_response(
856 flask.render_template("coprs/copr-modules.cfg", copr=copr, module=module,
857 baseurl=baseurl, pubkey_url=pubkey_url))
858 response.mimetype = "text/plain"
859 response.headers["Content-Disposition"] = \
860 "filename={0}.cfg".format(copr.repo_name)
861 return response
862
863
864
865 @coprs_ns.route("/<username>/<coprname>/rpm/<name_release>/<rpmfile>")
866 -def copr_repo_rpm_file(username, coprname, name_release, rpmfile):
867 try:
868 packages_dir = os.path.join(app.config["DATA_DIR"], "repo-rpm-packages")
869 with open(os.path.join(packages_dir, rpmfile), "rb") as rpm:
870 response = flask.make_response(rpm.read())
871 response.mimetype = "application/x-rpm"
872 response.headers["Content-Disposition"] = \
873 "filename={0}".format(rpmfile)
874 return response
875 except IOError:
876 return flask.render_template("404.html")
877
894
895
896 @coprs_ns.route("/<username>/<coprname>/monitor/")
897 @coprs_ns.route("/<username>/<coprname>/monitor/<detailed>")
898 @req_with_copr
899 -def copr_build_monitor(copr, detailed=False):
901
902
903 @coprs_ns.route("/g/<group_name>/<coprname>/monitor/")
904 @coprs_ns.route("/g/<group_name>/<coprname>/monitor/<detailed>")
905 @req_with_copr
906 -def group_copr_build_monitor(copr, detailed=False):
908
909
910 @coprs_ns.route("/<username>/<coprname>/fork/")
911 @coprs_ns.route("/g/<group_name>/<coprname>/fork/")
912 @login_required
913 @req_with_copr
914 -def copr_fork(copr):
917
920 return flask.render_template("coprs/fork.html", copr=copr, form=form, confirm=confirm)
921
922
923 @coprs_ns.route("/<username>/<coprname>/fork/", methods=["POST"])
924 @coprs_ns.route("/g/<group_name>/<coprname>/fork/", methods=["POST"])
925 @login_required
926 @req_with_copr
927 -def copr_fork_post(copr):
928 form = forms.CoprForkFormFactory.create_form_cls(copr=copr, user=flask.g.user, groups=flask.g.user.user_groups)()
929 if form.validate_on_submit():
930 dstgroup = ([g for g in flask.g.user.user_groups if g.at_name == form.owner.data] or [None])[0]
931 if flask.g.user.name != form.owner.data and not dstgroup:
932 return generic_error("There is no such group: {}".format(form.owner.data))
933
934 fcopr, created = ComplexLogic.fork_copr(copr, flask.g.user, dstname=form.name.data, dstgroup=dstgroup)
935 if created:
936 msg = ("Forking project {} for you into {}. Please be aware that it may take a few minutes "
937 "to duplicate backend data.".format(copr.full_name, fcopr.full_name))
938 elif not created and form.confirm.data == True:
939 msg = ("Updating packages in {} from {}. Please be aware that it may take a few minutes "
940 "to duplicate backend data.".format(copr.full_name, fcopr.full_name))
941 else:
942 return render_copr_fork(copr, form, confirm=True)
943
944 db.session.commit()
945 flask.flash(msg)
946
947 return flask.redirect(url_for_copr_details(fcopr))
948 return render_copr_fork(copr, form)
949
953 subprocess.call(['/usr/share/copr/coprs_frontend/manage.py', 'update_indexes_quick', '1'])
954 return "OK"
955
956
957 @coprs_ns.route("/<username>/<coprname>/modules/")
958 @coprs_ns.route("/g/<group_name>/<coprname>/modules/")
959 @req_with_copr
960 -def copr_modules(copr):
962
967
968
969 @coprs_ns.route("/<username>/<coprname>/create_module/")
970 @coprs_ns.route("/g/<group_name>/<coprname>/create_module/")
971 @login_required
972 @req_with_copr
973 -def copr_create_module(copr):
976
985
986
987 @coprs_ns.route("/<username>/<coprname>/create_module/", methods=["POST"])
988 @coprs_ns.route("/g/<group_name>/<coprname>/create_module/", methods=["POST"])
989 @login_required
990 @req_with_copr
991 -def copr_create_module_post(copr):
992 form = forms.CreateModuleForm(copr=copr, csrf_enabled=False)
993 args = [copr, form]
994 if "add_profile" in flask.request.values:
995 return add_profile(*args)
996 if "build_module" in flask.request.values:
997 return build_module(*args)
998
1007
1010 if not form.validate_on_submit():
1011
1012 for i in range(2, len(form.profile_names)):
1013 form.profile_pkgs.append_entry()
1014 return render_create_module(copr, form, profiles=len(form.profile_names))
1015
1016 summary = "Module from Copr repository: {}".format(copr.full_name)
1017 generator = ModulemdGenerator(str(copr.name), summary=summary, config=app.config)
1018 generator.add_filter(form.filter.data)
1019 generator.add_api(form.api.data)
1020 generator.add_profiles(enumerate(zip(form.profile_names.data, form.profile_pkgs.data)))
1021 generator.add_components(form.packages.data, form.filter.data, form.builds.data)
1022 yaml = generator.generate()
1023
1024 facade = None
1025 try:
1026 facade = ModuleBuildFacade(flask.g.user, copr, yaml)
1027 module = facade.submit_build()
1028 db.session.commit()
1029
1030 flask.flash("Modulemd yaml file successfully generated and submitted to be build as {}"
1031 .format(module.nsv), "success")
1032 return flask.redirect(url_for_copr_details(copr))
1033
1034 except ValidationError as ex:
1035 flask.flash(ex.message, "error")
1036 return render_create_module(copr, form, len(form.profile_names))
1037
1038 except sqlalchemy.exc.IntegrityError:
1039 flask.flash("Module {}-{}-{} already exists".format(
1040 facade.modulemd.name, facade.modulemd.stream, facade.modulemd.version), "error")
1041 db.session.rollback()
1042 return render_create_module(copr, form, len(form.profile_names))
1043
1044
1045 @coprs_ns.route("/<username>/<coprname>/module/<id>")
1046 @coprs_ns.route("/g/<group_name>/<coprname>/module/<id>")
1047 @req_with_copr
1048 -def copr_module(copr, id):
1066
1067
1068 @coprs_ns.route("/<username>/<coprname>/module/<id>/raw")
1069 @coprs_ns.route("/g/<group_name>/<coprname>/module/<id>/raw")
1070 @req_with_copr
1071 -def copr_module_raw(copr, id):
1078