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_running_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_running_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 @coprs_ns.route("/g/<group_name>/add/")
147 @login_required
148 -def copr_add(username=None, group_name=None):
154
155
156 @coprs_ns.route("/<username>/new/", methods=["POST"])
157 @coprs_ns.route("/g/<group_name>/new/", methods=["POST"])
158 @login_required
159 -def copr_new(username=None, group_name=None):
163
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
203 """
204 Receive information from the user on how to create its new copr
205 and create it accordingly.
206 """
207
208 form = forms.CoprFormFactory.create_form_cls()()
209 if form.validate_on_submit():
210 try:
211 copr = coprs_logic.CoprsLogic.add(
212 flask.g.user,
213 name=form.name.data,
214 homepage=form.homepage.data,
215 contact=form.contact.data,
216 repos=form.repos.data.replace("\n", " "),
217 selected_chroots=form.selected_chroots,
218 description=form.description.data,
219 instructions=form.instructions.data,
220 disable_createrepo=form.disable_createrepo.data,
221 build_enable_net=form.build_enable_net.data,
222 unlisted_on_hp=form.unlisted_on_hp.data,
223 persistent=form.persistent.data,
224 auto_prune=(form.auto_prune.data if flask.g.user.admin else True),
225 use_bootstrap_container=form.use_bootstrap_container.data,
226 follow_fedora_branching=form.follow_fedora_branching.data,
227 )
228 except (exceptions.DuplicateException, exceptions.NonAdminCannotCreatePersistentProject) as e:
229 flask.flash(str(e), "error")
230 return flask.render_template("coprs/add.html", form=form)
231
232 db.session.commit()
233 after_the_project_creation(copr, form)
234
235 return flask.redirect(url_for_copr_details(copr))
236 else:
237 return flask.render_template("coprs/add.html", form=form)
238
241 flask.flash("New project has been created successfully.", "success")
242 _check_rpmfusion(copr.repos)
243 if form.initial_pkgs.data:
244 pkgs = form.initial_pkgs.data.replace("\n", " ").split(" ")
245
246
247 bad_urls = []
248 for pkg in pkgs:
249 if not pkg.endswith(".src.rpm"):
250 bad_urls.append(pkg)
251 flask.flash("Bad url: {0} (skipped)".format(pkg))
252 for bad_url in bad_urls:
253 pkgs.remove(bad_url)
254
255 if not pkgs:
256 flask.flash("No initial packages submitted")
257 else:
258
259 for pkg in pkgs:
260 builds_logic.BuildsLogic.add(
261 flask.g.user,
262 pkgs=pkg,
263 srpm_url=pkg,
264 copr=copr,
265 enable_net=form.build_enable_net.data
266 )
267
268 db.session.commit()
269 flask.flash("Initial packages were successfully submitted "
270 "for building.")
271
272
273 @coprs_ns.route("/<username>/<coprname>/report-abuse")
274 @coprs_ns.route("/g/<group_name>/<coprname>/report-abuse")
275 @req_with_copr
276 @login_required
277 -def copr_report_abuse(copr):
279
284
285
286 @coprs_ns.route("/<username>/<coprname>/")
287 @coprs_ns.route("/g/<group_name>/<coprname>/")
288 @req_with_copr
289 -def copr_detail(copr):
291
294 repo_dl_stat = CounterStatLogic.get_copr_repo_dl_stat(copr)
295 form = forms.CoprLegalFlagForm()
296 repos_info = {}
297 for chroot in copr.active_chroots:
298
299
300
301
302
303 chroot_rpms_dl_stat_key = CHROOT_RPMS_DL_STAT_FMT.format(
304 copr_user=copr.owner_name,
305 copr_project_name=copr.name,
306 copr_chroot=chroot.name,
307 )
308 chroot_rpms_dl_stat = TimedStatEvents.get_count(
309 rconnect=rcp.get_connection(),
310 name=chroot_rpms_dl_stat_key,
311 )
312
313 logoset = set()
314 logodir = app.static_folder + "/chroot_logodir"
315 for logo in os.listdir(logodir):
316
317 if fnmatch.fnmatch(logo, "*.png"):
318 logoset.add(logo[:-4])
319
320 if chroot.name_release not in repos_info:
321 logo = None
322 if chroot.name_release in logoset:
323 logo = chroot.name_release + ".png"
324 elif chroot.os_release in logoset:
325 logo = chroot.os_release + ".png"
326
327 repos_info[chroot.name_release] = {
328 "name_release": chroot.name_release,
329 "os_release": chroot.os_release,
330 "os_version": chroot.os_version,
331 "logo": logo,
332 "arch_list": [chroot.arch],
333 "repo_file": "{}-{}.repo".format(copr.repo_id, chroot.name_release),
334 "dl_stat": repo_dl_stat[chroot.name_release],
335 "rpm_dl_stat": {
336 chroot.arch: chroot_rpms_dl_stat
337 }
338 }
339 else:
340 repos_info[chroot.name_release]["arch_list"].append(chroot.arch)
341 repos_info[chroot.name_release]["rpm_dl_stat"][chroot.arch] = chroot_rpms_dl_stat
342 repos_info_list = sorted(repos_info.values(), key=lambda rec: rec["name_release"])
343 builds = builds_logic.BuildsLogic.get_multiple_by_copr(copr=copr).limit(1).all()
344
345 return flask.render_template(
346 "coprs/detail/overview.html",
347 copr=copr,
348 user=flask.g.user,
349 form=form,
350 repo_dl_stat=repo_dl_stat,
351 repos_info_list=repos_info_list,
352 latest_build=builds[0] if len(builds) == 1 else None,
353 )
354
355
356 @coprs_ns.route("/<username>/<coprname>/permissions/")
357 @req_with_copr
358 -def copr_permissions(copr):
386
389 if not copr.webhook_secret:
390 copr.webhook_secret = str(uuid.uuid4())
391 db.session.add(copr)
392 db.session.commit()
393
394 bitbucket_url = "https://{}/webhooks/bitbucket/{}/{}/".format(
395 app.config["PUBLIC_COPR_HOSTNAME"],
396 copr.id,
397 copr.webhook_secret)
398
399 github_url = "https://{}/webhooks/github/{}/{}/".format(
400 app.config["PUBLIC_COPR_HOSTNAME"],
401 copr.id,
402 copr.webhook_secret)
403
404 gitlab_url = "https://{}/webhooks/gitlab/{}/{}/".format(
405 app.config["PUBLIC_COPR_HOSTNAME"],
406 copr.id,
407 copr.webhook_secret)
408
409 custom_url = "https://{}/webhooks/custom/{}/{}/".format(
410 app.config["PUBLIC_COPR_HOSTNAME"],
411 copr.id,
412 copr.webhook_secret) + "<PACKAGE_NAME>/"
413
414 return flask.render_template(
415 "coprs/detail/settings/webhooks.html",
416 copr=copr, bitbucket_url=bitbucket_url, github_url=github_url,
417 gitlab_url=gitlab_url, custom_url=custom_url)
418
419
420 @coprs_ns.route("/<username>/<coprname>/webhooks/")
421 @coprs_ns.route("/g/<group_name>/<coprname>/webhooks/")
422 @login_required
423 @req_with_copr
424 -def copr_webhooks(copr):
426
435
436
437 @coprs_ns.route("/<username>/<coprname>/edit/")
438 @coprs_ns.route("/g/<group_name>/<coprname>/edit/")
439 @login_required
440 @req_with_copr
441 -def copr_edit(copr, form=None):
443
446 if "rpmfusion" in repos:
447 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>.')
448 flask.flash(message, "error")
449
481
482
483 @coprs_ns.route("/<username>/<coprname>/update/", methods=["POST"])
484 @coprs_ns.route("/g/<group_name>/<coprname>/update/", methods=["POST"])
485 @login_required
486 @req_with_copr
487 -def copr_update(copr):
495
496
497 @coprs_ns.route("/<username>/<coprname>/permissions_applier_change/",
498 methods=["POST"])
502 permission = coprs_logic.CoprPermissionsLogic.get(copr, flask.g.user).first()
503 applier_permissions_form = \
504 forms.PermissionsApplierFormFactory.create_form_cls(permission)()
505
506 if copr.user == flask.g.user:
507 flask.flash("Owner cannot request permissions for his own project.", "error")
508 elif applier_permissions_form.validate_on_submit():
509
510 if permission is not None:
511 old_builder = permission.copr_builder
512 old_admin = permission.copr_admin
513 else:
514 old_builder = 0
515 old_admin = 0
516 new_builder = applier_permissions_form.copr_builder.data
517 new_admin = applier_permissions_form.copr_admin.data
518 coprs_logic.CoprPermissionsLogic.update_permissions_by_applier(
519 flask.g.user, copr, permission, new_builder, new_admin)
520 db.session.commit()
521 flask.flash(
522 "Successfully updated permissions for project '{0}'."
523 .format(copr.name))
524 admin_mails = [copr.user.mail]
525 for perm in copr.copr_permissions:
526
527 if perm.copr_admin == 2:
528 admin_mails.append(perm.user.mail)
529
530
531 if flask.current_app.config.get("SEND_EMAILS", False):
532 for mail in admin_mails:
533 msg = MIMEText(
534 "{6} is asking for these permissions:\n\n"
535 "Builder: {0} -> {1}\nAdmin: {2} -> {3}\n\n"
536 "Project: {4}\nOwner: {5}".format(
537 helpers.PermissionEnum(old_builder),
538 helpers.PermissionEnum(new_builder),
539 helpers.PermissionEnum(old_admin),
540 helpers.PermissionEnum(new_admin),
541 copr.name, copr.user.name, flask.g.user.name))
542
543 msg["Subject"] = "[Copr] {0}: {1} is asking permissions".format(copr.name, flask.g.user.name)
544 msg["From"] = "root@{0}".format(platform.node())
545 msg["To"] = mail
546 s = smtplib.SMTP("localhost")
547 s.sendmail("root@{0}".format(platform.node()), mail, msg.as_string())
548 s.quit()
549
550 return flask.redirect(flask.url_for("coprs_ns.copr_detail",
551 username=copr.user.name,
552 coprname=copr.name))
553
554
555 @coprs_ns.route("/<username>/<coprname>/update_permissions/", methods=["POST"])
556 @login_required
557 @req_with_copr
558 -def copr_update_permissions(copr):
559 permissions = copr.copr_permissions
560 permissions_form = forms.PermissionsFormFactory.create_form_cls(
561 permissions)()
562
563 if permissions_form.validate_on_submit():
564
565 try:
566
567
568 permissions.sort(
569 key=lambda x: -1 if x.user_id == flask.g.user.id else 1)
570 for perm in permissions:
571 old_builder = perm.copr_builder
572 old_admin = perm.copr_admin
573 new_builder = permissions_form[
574 "copr_builder_{0}".format(perm.user_id)].data
575 new_admin = permissions_form[
576 "copr_admin_{0}".format(perm.user_id)].data
577 coprs_logic.CoprPermissionsLogic.update_permissions(
578 flask.g.user, copr, perm, new_builder, new_admin)
579 if flask.current_app.config.get("SEND_EMAILS", False) and \
580 (old_builder is not new_builder or old_admin is not new_admin):
581
582 msg = MIMEText(
583 "Your permissions have changed:\n\n"
584 "Builder: {0} -> {1}\nAdmin: {2} -> {3}\n\n"
585 "Project: {4}\nOwner: {5}".format(
586 helpers.PermissionEnum(old_builder),
587 helpers.PermissionEnum(new_builder),
588 helpers.PermissionEnum(old_admin),
589 helpers.PermissionEnum(new_admin),
590 copr.name, copr.user.name))
591
592 msg["Subject"] = "[Copr] {0}: Your permissions have changed".format(copr.name)
593 msg["From"] = "root@{0}".format(platform.node())
594 msg["To"] = perm.user.mail
595 s = smtplib.SMTP("localhost")
596 s.sendmail("root@{0}".format(platform.node()), perm.user.mail, msg.as_string())
597 s.quit()
598
599
600 except exceptions.InsufficientRightsException as e:
601 db.session.rollback()
602 flask.flash(str(e), "error")
603 else:
604 db.session.commit()
605 flask.flash("Project permissions were updated successfully.", "success")
606
607 return flask.redirect(url_for_copr_details(copr))
608
609
610 @coprs_ns.route("/id/<copr_id>/createrepo/", methods=["POST"])
611 @login_required
612 -def copr_createrepo(copr_id):
627
630 form = forms.CoprDeleteForm()
631 if form.validate_on_submit():
632
633 try:
634 ComplexLogic.delete_copr(copr)
635 except (exceptions.ActionInProgressException,
636 exceptions.InsufficientRightsException) as e:
637
638 db.session.rollback()
639 flask.flash(str(e), "error")
640 return flask.redirect(url_on_error)
641 else:
642 db.session.commit()
643 flask.flash("Project has been deleted successfully.")
644 return flask.redirect(url_on_success)
645 else:
646 return render_template("coprs/detail/settings/delete.html", form=form, copr=copr)
647
648
649 @coprs_ns.route("/<username>/<coprname>/delete/", methods=["GET", "POST"])
650 @coprs_ns.route("/g/<group_name>/<coprname>/delete/", methods=["GET", "POST"])
651 @login_required
652 @req_with_copr
653 -def copr_delete(copr):
660
661
662 @coprs_ns.route("/<username>/<coprname>/legal_flag/", methods=["POST"])
663 @coprs_ns.route("/g/<group_name>/<coprname>/legal_flag/", methods=["POST"])
664 @login_required
665 @req_with_copr
666 -def copr_legal_flag(copr):
669
672 form = forms.CoprLegalFlagForm()
673 legal_flag = models.LegalFlag(raise_message=form.comment.data,
674 raised_on=int(time.time()),
675 copr=copr,
676 reporter=flask.g.user)
677 db.session.add(legal_flag)
678 db.session.commit()
679 send_to = app.config["SEND_LEGAL_TO"] or ["root@localhost"]
680 hostname = platform.node()
681 navigate_to = "\nNavigate to http://{0}{1}".format(
682 hostname, flask.url_for("admin_ns.legal_flag"))
683 contact = "\nContact on owner is: {}".format(contact_info)
684 reported_by = "\nReported by {0} <{1}>".format(flask.g.user.name,
685 flask.g.user.mail)
686 try:
687 msg = MIMEText(
688 form.comment.data + navigate_to + contact + reported_by, "plain")
689 except UnicodeEncodeError:
690 msg = MIMEText(form.comment.data.encode(
691 "utf-8") + navigate_to + contact + reported_by, "plain", "utf-8")
692 msg["Subject"] = "Legal flag raised on {0}".format(copr.name)
693 msg["From"] = "root@{0}".format(hostname)
694 msg["To"] = ", ".join(send_to)
695 s = smtplib.SMTP("localhost")
696 s.sendmail("root@{0}".format(hostname), send_to, msg.as_string())
697 s.quit()
698 flask.flash("Admin has been noticed about your report"
699 " and will investigate the project shortly.")
700 return flask.redirect(url_for_copr_details(copr))
701
702
703 @coprs_ns.route("/<username>/<coprname>/repo/<name_release>/", defaults={"repofile": None})
704 @coprs_ns.route("/<username>/<coprname>/repo/<name_release>/<repofile>")
705 @coprs_ns.route("/g/<group_name>/<coprname>/repo/<name_release>/", defaults={"repofile": None})
706 @coprs_ns.route("/g/<group_name>/<coprname>/repo/<name_release>/<repofile>")
707 -def generate_repo_file(coprname, name_release, repofile, username=None, group_name=None):
720
723 mock_chroot = coprs_logic.MockChrootsLogic.get_from_name(name_release, noarch=True).first()
724
725 if not mock_chroot:
726 raise ObjectNotFound("Chroot {} does not exist".format(name_release))
727
728 url = os.path.join(copr.repo_url, '')
729 repo_url = generate_repo_url(mock_chroot, url)
730 pubkey_url = urljoin(url, "pubkey.gpg")
731 response = flask.make_response(
732 flask.render_template("coprs/copr.repo", copr=copr, url=repo_url, pubkey_url=pubkey_url))
733 response.mimetype = "text/plain"
734 response.headers["Content-Disposition"] = \
735 "filename={0}.repo".format(copr.repo_name)
736
737 name = REPO_DL_STAT_FMT.format(**{
738 'copr_user': copr.user.name,
739 'copr_project_name': copr.name,
740 'copr_name_release': name_release,
741 })
742 CounterStatLogic.incr(name=name, counter_type=CounterStatType.REPO_DL)
743 db.session.commit()
744
745 return response
746
747
748
749
750
751
752 @coprs_ns.route("/<username>/<coprname>/module_repo/<name_release>/<module_nsv>.repo")
753 @coprs_ns.route("/g/<group_name>/<coprname>/module_repo/<name_release>/<module_nsv>.repo")
754 @req_with_copr
755 -def generate_module_repo_file(copr, name_release, module_nsv):
758
760 module = ModulesLogic.get_by_nsv_str(copr, module_nsv).one()
761 mock_chroot = coprs_logic.MockChrootsLogic.get_from_name(name_release, noarch=True).first()
762 url = os.path.join(copr.repo_url, '')
763 repo_url = generate_repo_url(mock_chroot, copr.modules_url)
764 baseurl = "{}+{}/latest/$basearch".format(repo_url.rstrip("/"), module_nsv)
765 pubkey_url = urljoin(url, "pubkey.gpg")
766 response = flask.make_response(
767 flask.render_template("coprs/copr-modules.cfg", copr=copr, module=module,
768 baseurl=baseurl, pubkey_url=pubkey_url))
769 response.mimetype = "text/plain"
770 response.headers["Content-Disposition"] = \
771 "filename={0}.cfg".format(copr.repo_name)
772 return response
773
774
775
776 @coprs_ns.route("/<username>/<coprname>/rpm/<name_release>/<rpmfile>")
777 -def copr_repo_rpm_file(username, coprname, name_release, rpmfile):
778 try:
779 packages_dir = os.path.join(app.config["DATA_DIR"], "repo-rpm-packages")
780 with open(os.path.join(packages_dir, rpmfile), "rb") as rpm:
781 response = flask.make_response(rpm.read())
782 response.mimetype = "application/x-rpm"
783 response.headers["Content-Disposition"] = \
784 "filename={0}".format(rpmfile)
785 return response
786 except IOError:
787 return flask.render_template("404.html")
788
805
806
807 @coprs_ns.route("/<username>/<coprname>/monitor/")
808 @coprs_ns.route("/<username>/<coprname>/monitor/<detailed>")
809 @coprs_ns.route("/g/<group_name>/<coprname>/monitor/")
810 @coprs_ns.route("/g/<group_name>/<coprname>/monitor/<detailed>")
811 @req_with_copr
812 -def copr_build_monitor(copr, detailed=False):
814
815
816 @coprs_ns.route("/<username>/<coprname>/fork/")
817 @coprs_ns.route("/g/<group_name>/<coprname>/fork/")
818 @login_required
819 @req_with_copr
820 -def copr_fork(copr):
823
826 return flask.render_template("coprs/fork.html", copr=copr, form=form, confirm=confirm)
827
828
829 @coprs_ns.route("/<username>/<coprname>/fork/", methods=["POST"])
830 @coprs_ns.route("/g/<group_name>/<coprname>/fork/", methods=["POST"])
831 @login_required
832 @req_with_copr
833 -def copr_fork_post(copr):
834 form = forms.CoprForkFormFactory.create_form_cls(copr=copr, user=flask.g.user, groups=flask.g.user.user_groups)()
835 if form.validate_on_submit():
836 dstgroup = ([g for g in flask.g.user.user_groups if g.at_name == form.owner.data] or [None])[0]
837 if flask.g.user.name != form.owner.data and not dstgroup:
838 return generic_error("There is no such group: {}".format(form.owner.data))
839
840 fcopr, created = ComplexLogic.fork_copr(copr, flask.g.user, dstname=form.name.data, dstgroup=dstgroup)
841 if created:
842 msg = ("Forking project {} for you into {}. Please be aware that it may take a few minutes "
843 "to duplicate backend data.".format(copr.full_name, fcopr.full_name))
844 elif not created and form.confirm.data == True:
845 msg = ("Updating packages in {} from {}. Please be aware that it may take a few minutes "
846 "to duplicate backend data.".format(copr.full_name, fcopr.full_name))
847 else:
848 return render_copr_fork(copr, form, confirm=True)
849
850 db.session.commit()
851 flask.flash(msg)
852
853 return flask.redirect(url_for_copr_details(fcopr))
854 return render_copr_fork(copr, form)
855
859 subprocess.call(['/usr/share/copr/coprs_frontend/manage.py', 'update_indexes_quick', '1'])
860 return "OK"
861
862
863 @coprs_ns.route("/<username>/<coprname>/modules/")
864 @coprs_ns.route("/g/<group_name>/<coprname>/modules/")
865 @req_with_copr
866 -def copr_modules(copr):
868
873
874
875 @coprs_ns.route("/<username>/<coprname>/create_module/")
876 @coprs_ns.route("/g/<group_name>/<coprname>/create_module/")
877 @login_required
878 @req_with_copr
879 -def copr_create_module(copr):
882
891
892
893 @coprs_ns.route("/<username>/<coprname>/create_module/", methods=["POST"])
894 @coprs_ns.route("/g/<group_name>/<coprname>/create_module/", methods=["POST"])
895 @login_required
896 @req_with_copr
897 -def copr_create_module_post(copr):
898 form = forms.CreateModuleForm(copr=copr, csrf_enabled=False)
899 args = [copr, form]
900 if "add_profile" in flask.request.values:
901 return add_profile(*args)
902 if "build_module" in flask.request.values:
903 return build_module(*args)
904
913
916 if not form.validate_on_submit():
917
918 for i in range(2, len(form.profile_names)):
919 form.profile_pkgs.append_entry()
920 return render_create_module(copr, form, profiles=len(form.profile_names))
921
922 summary = "Module from Copr repository: {}".format(copr.full_name)
923 generator = ModulemdGenerator(str(copr.name), summary=summary, config=app.config)
924 generator.add_filter(form.filter.data)
925 generator.add_api(form.api.data)
926 generator.add_profiles(enumerate(zip(form.profile_names.data, form.profile_pkgs.data)))
927 generator.add_components(form.packages.data, form.filter.data, form.builds.data)
928 yaml = generator.generate()
929
930 facade = None
931 try:
932 facade = ModuleBuildFacade(flask.g.user, copr, yaml)
933 module = facade.submit_build()
934 db.session.commit()
935
936 flask.flash("Modulemd yaml file successfully generated and submitted to be build as {}"
937 .format(module.nsv), "success")
938 return flask.redirect(url_for_copr_details(copr))
939
940 except ValidationError as ex:
941 flask.flash(ex.message, "error")
942 return render_create_module(copr, form, len(form.profile_names))
943
944 except sqlalchemy.exc.IntegrityError:
945 flask.flash("Module {}-{}-{} already exists".format(
946 facade.modulemd.name, facade.modulemd.stream, facade.modulemd.version), "error")
947 db.session.rollback()
948 return render_create_module(copr, form, len(form.profile_names))
949
950
951 @coprs_ns.route("/<username>/<coprname>/module/<id>")
952 @coprs_ns.route("/g/<group_name>/<coprname>/module/<id>")
953 @req_with_copr
954 -def copr_module(copr, id):
972
973
974 @coprs_ns.route("/<username>/<coprname>/module/<id>/raw")
975 @coprs_ns.route("/g/<group_name>/<coprname>/module/<id>/raw")
976 @req_with_copr
977 -def copr_module_raw(copr, id):
984