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