1
2
3 import os
4 import time
5 import fnmatch
6 import uuid
7 import subprocess
8 import json
9
10 from six.moves.urllib.parse import urljoin
11
12 import flask
13 from flask import render_template, url_for, stream_with_context
14 import platform
15 import smtplib
16 import tempfile
17 import sqlalchemy
18 from email.mime.text import MIMEText
19 from itertools import groupby
20 from wtforms import ValidationError
21
22 from pygments import highlight
23 from pygments.lexers import get_lexer_by_name
24 from pygments.formatters import HtmlFormatter
25
26 from copr_common.enums import StatusEnum
27 from coprs import app
28 from coprs import db
29 from coprs import rcp
30 from coprs import exceptions
31 from coprs import forms
32 from coprs import helpers
33 from coprs import models
34 from coprs.exceptions import ObjectNotFound
35 from coprs.logic.coprs_logic import CoprsLogic
36 from coprs.logic.packages_logic import PackagesLogic
37 from coprs.logic.stat_logic import CounterStatLogic
38 from coprs.logic.modules_logic import ModulesLogic, ModulemdGenerator, ModuleBuildFacade
39 from coprs.rmodels import TimedStatEvents
40 from coprs.mail import send_mail, LegalFlagMessage, PermissionRequestMessage, PermissionChangeMessage
41
42 from coprs.logic.complex_logic import ComplexLogic
43
44 from coprs.views.misc import login_required, page_not_found, req_with_copr, req_with_copr, generic_error
45
46 from coprs.views.coprs_ns import coprs_ns
47 from coprs.views.groups_ns import groups_ns
48
49 from coprs.logic import builds_logic, coprs_logic, actions_logic, users_logic
50 from coprs.helpers import parse_package_name, generate_repo_url, CHROOT_RPMS_DL_STAT_FMT, CHROOT_REPO_MD_DL_STAT_FMT, \
51 str2bool, url_for_copr_view, REPO_DL_STAT_FMT, CounterStatType
58
65
66
67 @coprs_ns.route("/", defaults={"page": 1})
68 @coprs_ns.route("/<int:page>/")
69 -def coprs_show(page=1):
90
91
92 @coprs_ns.route("/<username>/", defaults={"page": 1})
93 @coprs_ns.route("/<username>/<int:page>/")
94 -def coprs_by_user(username=None, page=1):
95 user = users_logic.UsersLogic.get(username).first()
96 if not user:
97 return page_not_found(
98 "User {0} does not exist.".format(username))
99
100 query = CoprsLogic.get_multiple_owned_by_username(username)
101 query = CoprsLogic.filter_without_group_projects(query)
102 query = CoprsLogic.set_query_order(query, desc=True)
103
104 paginator = helpers.Paginator(query, query.count(), page)
105
106 coprs = paginator.sliced_query
107
108
109 users_builds = builds_logic.BuildsLogic.get_recent_tasks(flask.g.user, 4)
110
111 data = builds_logic.BuildsLogic.get_small_graph_data('30min')
112
113 return flask.render_template("coprs/show/user.html",
114 user=user,
115 coprs=coprs,
116 paginator=paginator,
117 tasks_info=ComplexLogic.get_queue_sizes(),
118 users_builds=users_builds,
119 graph=data)
120
121
122 @coprs_ns.route("/fulltext/", defaults={"page": 1})
123 @coprs_ns.route("/fulltext/<int:page>/")
124 -def coprs_fulltext_search(page=1):
125 fulltext = flask.request.args.get("fulltext", "")
126 try:
127 query = coprs_logic.CoprsLogic.get_multiple_fulltext(fulltext)
128 except ValueError as e:
129 flask.flash(str(e), "error")
130 return flask.redirect(flask.request.referrer or
131 flask.url_for("coprs_ns.coprs_show"))
132
133 paginator = helpers.Paginator(query, query.count(), page,
134 additional_params={"fulltext": fulltext})
135
136 data = builds_logic.BuildsLogic.get_small_graph_data('30min')
137
138 coprs = paginator.sliced_query
139 return render_template("coprs/show/fulltext.html",
140 coprs=coprs,
141 paginator=paginator,
142 fulltext=fulltext,
143 tasks_info=ComplexLogic.get_queue_sizes(),
144 graph=data)
145
146
147 @coprs_ns.route("/<username>/add/")
148 @coprs_ns.route("/g/<group_name>/add/")
149 @login_required
150 -def copr_add(username=None, group_name=None):
156
157
158 @coprs_ns.route("/<username>/new/", methods=["POST"])
159 @coprs_ns.route("/g/<group_name>/new/", methods=["POST"])
160 @login_required
161 -def copr_new(username=None, group_name=None):
165
168 group = ComplexLogic.get_group_by_name_safe(group_name)
169 form = forms.CoprFormFactory.create_form_cls(group=group)()
170
171 if form.validate_on_submit():
172 try:
173 copr = coprs_logic.CoprsLogic.add(
174 flask.g.user,
175 name=form.name.data,
176 homepage=form.homepage.data,
177 contact=form.contact.data,
178 repos=form.repos.data.replace("\n", " "),
179 selected_chroots=form.selected_chroots,
180 description=form.description.data,
181 instructions=form.instructions.data,
182 disable_createrepo=form.disable_createrepo.data,
183 build_enable_net=form.build_enable_net.data,
184 unlisted_on_hp=form.unlisted_on_hp.data,
185 group=group,
186 persistent=form.persistent.data,
187 auto_prune=(form.auto_prune.data if flask.g.user.admin else True),
188 use_bootstrap_container=form.use_bootstrap_container.data,
189 follow_fedora_branching=form.follow_fedora_branching.data,
190 )
191 except (exceptions.DuplicateException, exceptions.NonAdminCannotCreatePersistentProject) as e:
192 flask.flash(str(e), "error")
193 return flask.render_template("coprs/group_add.html", form=form, group=group)
194
195 db.session.add(copr)
196 db.session.commit()
197 after_the_project_creation(copr, form)
198
199 return flask.redirect(url_for_copr_details(copr))
200 else:
201 return flask.render_template("coprs/group_add.html", form=form, group=group)
202
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 @coprs_ns.route("/g/<group_name>/<coprname>/report-abuse")
277 @req_with_copr
278 @login_required
279 -def copr_report_abuse(copr):
281
286
287
288 @coprs_ns.route("/<username>/<coprname>/")
289 @coprs_ns.route("/g/<group_name>/<coprname>/")
290 @req_with_copr
291 -def copr_detail(copr):
293
296 repo_dl_stat = CounterStatLogic.get_copr_repo_dl_stat(copr)
297 form = forms.CoprLegalFlagForm()
298 repos_info = {}
299 for chroot in copr.active_chroots:
300
301
302
303
304
305 chroot_rpms_dl_stat_key = CHROOT_RPMS_DL_STAT_FMT.format(
306 copr_user=copr.owner_name,
307 copr_project_name=copr.name,
308 copr_chroot=chroot.name,
309 )
310 chroot_rpms_dl_stat = TimedStatEvents.get_count(
311 rconnect=rcp.get_connection(),
312 name=chroot_rpms_dl_stat_key,
313 )
314
315 logoset = set()
316 logodir = app.static_folder + "/chroot_logodir"
317 for logo in os.listdir(logodir):
318
319 if fnmatch.fnmatch(logo, "*.png"):
320 logoset.add(logo[:-4])
321
322 if chroot.name_release not in repos_info:
323 logo = None
324 if chroot.name_release in logoset:
325 logo = chroot.name_release + ".png"
326 elif chroot.os_release in logoset:
327 logo = chroot.os_release + ".png"
328
329 repos_info[chroot.name_release] = {
330 "name_release": chroot.name_release,
331 "os_release": chroot.os_release,
332 "os_version": chroot.os_version,
333 "logo": logo,
334 "arch_list": [chroot.arch],
335 "repo_file": "{}-{}.repo".format(copr.repo_id, chroot.name_release),
336 "dl_stat": repo_dl_stat[chroot.name_release],
337 "rpm_dl_stat": {
338 chroot.arch: chroot_rpms_dl_stat
339 }
340 }
341 else:
342 repos_info[chroot.name_release]["arch_list"].append(chroot.arch)
343 repos_info[chroot.name_release]["rpm_dl_stat"][chroot.arch] = chroot_rpms_dl_stat
344 repos_info_list = sorted(repos_info.values(), key=lambda rec: rec["name_release"])
345 builds = builds_logic.BuildsLogic.get_multiple_by_copr(copr=copr).limit(1).all()
346
347 return flask.render_template(
348 "coprs/detail/overview.html",
349 copr=copr,
350 user=flask.g.user,
351 form=form,
352 repo_dl_stat=repo_dl_stat,
353 repos_info_list=repos_info_list,
354 latest_build=builds[0] if len(builds) == 1 else None,
355 )
356
357
358 @coprs_ns.route("/<username>/<coprname>/permissions/")
359 @req_with_copr
360 -def copr_permissions(copr):
388
391 if not copr.webhook_secret:
392 copr.new_webhook_secret()
393 db.session.add(copr)
394 db.session.commit()
395
396 bitbucket_url = "https://{}/webhooks/bitbucket/{}/{}/".format(
397 app.config["PUBLIC_COPR_HOSTNAME"],
398 copr.id,
399 copr.webhook_secret)
400
401 github_url = "https://{}/webhooks/github/{}/{}/".format(
402 app.config["PUBLIC_COPR_HOSTNAME"],
403 copr.id,
404 copr.webhook_secret)
405
406 gitlab_url = "https://{}/webhooks/gitlab/{}/{}/".format(
407 app.config["PUBLIC_COPR_HOSTNAME"],
408 copr.id,
409 copr.webhook_secret)
410
411 custom_url = "https://{}/webhooks/custom/{}/{}/".format(
412 app.config["PUBLIC_COPR_HOSTNAME"],
413 copr.id,
414 copr.webhook_secret) + "<PACKAGE_NAME>/"
415
416 return flask.render_template(
417 "coprs/detail/settings/integrations.html",
418 copr=copr, bitbucket_url=bitbucket_url, github_url=github_url,
419 gitlab_url=gitlab_url, custom_url=custom_url, pagure_form=pagure_form)
420
421
422 @coprs_ns.route("/<username>/<coprname>/integrations/")
423 @coprs_ns.route("/g/<group_name>/<coprname>/integrations/")
424 @login_required
425 @req_with_copr
426 -def copr_integrations(copr):
439
440
441 @coprs_ns.route("/<username>/<coprname>/integrations/update", methods=["POST"])
442 @coprs_ns.route("/g/<group_name>/<coprname>/integrations/update", methods=["POST"])
443 @login_required
444 @req_with_copr
445 -def copr_integrations_update(copr):
462
471
472
473 @coprs_ns.route("/<username>/<coprname>/edit/")
474 @coprs_ns.route("/g/<group_name>/<coprname>/edit/")
475 @login_required
476 @req_with_copr
477 -def copr_edit(copr, form=None):
479
482 if "rpmfusion" in repos:
483 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>.')
484 flask.flash(message, "error")
485
517
518
519 @coprs_ns.route("/<username>/<coprname>/update/", methods=["POST"])
520 @coprs_ns.route("/g/<group_name>/<coprname>/update/", methods=["POST"])
521 @login_required
522 @req_with_copr
523 -def copr_update(copr):
531
532
533 @coprs_ns.route("/<username>/<coprname>/permissions_applier_change/",
534 methods=["POST"])
538 permission = coprs_logic.CoprPermissionsLogic.get(copr, flask.g.user).first()
539 applier_permissions_form = \
540 forms.PermissionsApplierFormFactory.create_form_cls(permission)()
541
542 if copr.user == flask.g.user:
543 flask.flash("Owner cannot request permissions for his own project.", "error")
544 elif applier_permissions_form.validate_on_submit():
545
546 if permission is not None:
547 old_builder = permission.copr_builder
548 old_admin = permission.copr_admin
549 else:
550 old_builder = 0
551 old_admin = 0
552 new_builder = applier_permissions_form.copr_builder.data
553 new_admin = applier_permissions_form.copr_admin.data
554 coprs_logic.CoprPermissionsLogic.update_permissions_by_applier(
555 flask.g.user, copr, permission, new_builder, new_admin)
556 db.session.commit()
557 flask.flash(
558 "Successfully updated permissions for project '{0}'."
559 .format(copr.name))
560 admin_mails = [copr.user.mail]
561 for perm in copr.copr_permissions:
562
563 if perm.copr_admin == 2:
564 admin_mails.append(perm.user.mail)
565
566
567 if flask.current_app.config.get("SEND_EMAILS", False):
568 for mail in admin_mails:
569 permission_dict = {"old_builder": old_builder, "old_admin": old_admin,
570 "new_builder": new_builder, "new_admin": new_admin}
571 msg = PermissionRequestMessage(copr, flask.g.user, permission_dict)
572 send_mail(mail, msg, )
573
574 return flask.redirect(flask.url_for("coprs_ns.copr_detail",
575 username=copr.user.name,
576 coprname=copr.name))
577
578
579 @coprs_ns.route("/<username>/<coprname>/update_permissions/", methods=["POST"])
580 @login_required
581 @req_with_copr
582 -def copr_update_permissions(copr):
583 permissions = copr.copr_permissions
584 permissions_form = forms.PermissionsFormFactory.create_form_cls(
585 permissions)()
586
587 if permissions_form.validate_on_submit():
588
589 try:
590
591
592 permissions.sort(
593 key=lambda x: -1 if x.user_id == flask.g.user.id else 1)
594 for perm in permissions:
595 old_builder = perm.copr_builder
596 old_admin = perm.copr_admin
597 new_builder = permissions_form[
598 "copr_builder_{0}".format(perm.user_id)].data
599 new_admin = permissions_form[
600 "copr_admin_{0}".format(perm.user_id)].data
601 coprs_logic.CoprPermissionsLogic.update_permissions(
602 flask.g.user, copr, perm, new_builder, new_admin)
603 if flask.current_app.config.get("SEND_EMAILS", False) and \
604 (old_builder is not new_builder or old_admin is not new_admin):
605 permission_dict = {"old_builder": old_builder, "old_admin": old_admin,
606 "new_builder": new_builder, "new_admin": new_admin}
607 msg = PermissionChangeMessage(copr, permission_dict)
608 send_mail(perm.user.mail, msg)
609
610
611 except exceptions.InsufficientRightsException as e:
612 db.session.rollback()
613 flask.flash(str(e), "error")
614 else:
615 db.session.commit()
616 flask.flash("Project permissions were updated successfully.", "success")
617
618 return flask.redirect(url_for_copr_details(copr))
619
620
621 @coprs_ns.route("/id/<copr_id>/createrepo/", methods=["POST"])
622 @login_required
623 -def copr_createrepo(copr_id):
635
638 form = forms.CoprDeleteForm()
639 if form.validate_on_submit():
640
641 try:
642 ComplexLogic.delete_copr(copr)
643 except (exceptions.ActionInProgressException,
644 exceptions.InsufficientRightsException) as e:
645
646 db.session.rollback()
647 flask.flash(str(e), "error")
648 return flask.redirect(url_on_error)
649 else:
650 db.session.commit()
651 flask.flash("Project has been deleted successfully.")
652 return flask.redirect(url_on_success)
653 else:
654 return render_template("coprs/detail/settings/delete.html", form=form, copr=copr)
655
656
657 @coprs_ns.route("/<username>/<coprname>/delete/", methods=["GET", "POST"])
658 @coprs_ns.route("/g/<group_name>/<coprname>/delete/", methods=["GET", "POST"])
659 @login_required
660 @req_with_copr
661 -def copr_delete(copr):
668
669
670 @coprs_ns.route("/<username>/<coprname>/legal_flag/", methods=["POST"])
671 @coprs_ns.route("/g/<group_name>/<coprname>/legal_flag/", methods=["POST"])
672 @login_required
673 @req_with_copr
674 -def copr_legal_flag(copr):
676
694
695
696 @coprs_ns.route("/<username>/<copr_dirname>/repo/<name_release>/", defaults={"repofile": None})
697 @coprs_ns.route("/<username>/<copr_dirname>/repo/<name_release>/<repofile>")
698 @coprs_ns.route("/g/<group_name>/<copr_dirname>/repo/<name_release>/", defaults={"repofile": None})
699 @coprs_ns.route("/g/<group_name>/<copr_dirname>/repo/<name_release>/<repofile>")
700 -def generate_repo_file(copr_dirname, name_release, repofile, username=None, group_name=None):
707
710 mock_chroot = coprs_logic.MockChrootsLogic.get_from_name(name_release, noarch=True).first()
711
712 if not mock_chroot:
713 raise ObjectNotFound("Chroot {} does not exist".format(name_release))
714
715 repo_id = "copr:{0}:{1}:{2}".format(app.config["PUBLIC_COPR_HOSTNAME"],
716 copr_dir.copr.owner_name.replace("@", "group_"),
717 copr_dir.name)
718 url = os.path.join(copr_dir.repo_url, '')
719 repo_url = generate_repo_url(mock_chroot, url)
720 pubkey_url = urljoin(url, "pubkey.gpg")
721 response = flask.make_response(
722 flask.render_template("coprs/copr_dir.repo", copr_dir=copr_dir, url=repo_url, pubkey_url=pubkey_url,
723 repo_id=repo_id))
724 response.mimetype = "text/plain"
725 response.headers["Content-Disposition"] = \
726 "filename={0}.repo".format(copr_dir.repo_name)
727
728 name = REPO_DL_STAT_FMT.format(**{
729 'copr_user': copr_dir.copr.user.name,
730 'copr_project_name': copr_dir.copr.name,
731 'copr_name_release': name_release,
732 })
733 CounterStatLogic.incr(name=name, counter_type=CounterStatType.REPO_DL)
734 db.session.commit()
735
736 return response
737
738
739
740
741
742
743 @coprs_ns.route("/<username>/<coprname>/module_repo/<name_release>/<module_nsv>.repo")
744 @coprs_ns.route("/g/<group_name>/<coprname>/module_repo/<name_release>/<module_nsv>.repo")
745 @req_with_copr
746 -def generate_module_repo_file(copr, name_release, module_nsv):
749
751 module = ModulesLogic.get_by_nsv_str(copr, module_nsv).one()
752 mock_chroot = coprs_logic.MockChrootsLogic.get_from_name(name_release, noarch=True).first()
753 url = os.path.join(copr_dir.repo_url, '')
754 repo_url = generate_repo_url(mock_chroot, copr.modules_url)
755 baseurl = "{}+{}/latest/$basearch".format(repo_url.rstrip("/"), module_nsv)
756 pubkey_url = urljoin(url, "pubkey.gpg")
757 response = flask.make_response(
758 flask.render_template("coprs/copr-modules.cfg", copr=copr, module=module,
759 baseurl=baseurl, pubkey_url=pubkey_url))
760 response.mimetype = "text/plain"
761 response.headers["Content-Disposition"] = \
762 "filename={0}.cfg".format(copr.repo_name)
763 return response
764
765
766
767 @coprs_ns.route("/<username>/<coprname>/rpm/<name_release>/<rpmfile>")
768 -def copr_repo_rpm_file(username, coprname, name_release, rpmfile):
769 try:
770 packages_dir = os.path.join(app.config["DATA_DIR"], "repo-rpm-packages")
771 with open(os.path.join(packages_dir, rpmfile), "rb") as rpm:
772 response = flask.make_response(rpm.read())
773 response.mimetype = "application/x-rpm"
774 response.headers["Content-Disposition"] = \
775 "filename={0}".format(rpmfile)
776 return response
777 except IOError:
778 return flask.render_template("404.html")
779
796
797
798 @coprs_ns.route("/<username>/<coprname>/monitor/")
799 @coprs_ns.route("/<username>/<coprname>/monitor/<detailed>")
800 @coprs_ns.route("/g/<group_name>/<coprname>/monitor/")
801 @coprs_ns.route("/g/<group_name>/<coprname>/monitor/<detailed>")
802 @req_with_copr
803 -def copr_build_monitor(copr, detailed=False):
805
806
807 @coprs_ns.route("/<username>/<coprname>/fork/")
808 @coprs_ns.route("/g/<group_name>/<coprname>/fork/")
809 @login_required
810 @req_with_copr
811 -def copr_fork(copr):
814
817 return flask.render_template("coprs/fork.html", copr=copr, form=form, confirm=confirm)
818
819
820 @coprs_ns.route("/<username>/<coprname>/fork/", methods=["POST"])
821 @coprs_ns.route("/g/<group_name>/<coprname>/fork/", methods=["POST"])
822 @login_required
823 @req_with_copr
824 -def copr_fork_post(copr):
825 form = forms.CoprForkFormFactory.create_form_cls(copr=copr, user=flask.g.user, groups=flask.g.user.user_groups)()
826 if form.validate_on_submit():
827 dstgroup = ([g for g in flask.g.user.user_groups if g.at_name == form.owner.data] or [None])[0]
828 if flask.g.user.name != form.owner.data and not dstgroup:
829 return generic_error("There is no such group: {}".format(form.owner.data))
830
831 fcopr, created = ComplexLogic.fork_copr(copr, flask.g.user, dstname=form.name.data, dstgroup=dstgroup)
832 if created:
833 msg = ("Forking project {} for you into {}. Please be aware that it may take a few minutes "
834 "to duplicate backend data.".format(copr.full_name, fcopr.full_name))
835 elif not created and form.confirm.data == True:
836 msg = ("Updating packages in {} from {}. Please be aware that it may take a few minutes "
837 "to duplicate backend data.".format(copr.full_name, fcopr.full_name))
838 else:
839 return render_copr_fork(copr, form, confirm=True)
840
841 db.session.commit()
842 flask.flash(msg)
843
844 return flask.redirect(url_for_copr_details(fcopr))
845 return render_copr_fork(copr, form)
846
850 subprocess.call(['/usr/share/copr/coprs_frontend/manage.py', 'update_indexes_quick', '1'])
851 return "OK"
852
853
854 @coprs_ns.route("/<username>/<coprname>/modules/")
855 @coprs_ns.route("/g/<group_name>/<coprname>/modules/")
856 @req_with_copr
857 -def copr_modules(copr):
859
864
865
866 @coprs_ns.route("/<username>/<coprname>/create_module/")
867 @coprs_ns.route("/g/<group_name>/<coprname>/create_module/")
868 @login_required
869 @req_with_copr
870 -def copr_create_module(copr):
873
882
883
884 @coprs_ns.route("/<username>/<coprname>/create_module/", methods=["POST"])
885 @coprs_ns.route("/g/<group_name>/<coprname>/create_module/", methods=["POST"])
886 @login_required
887 @req_with_copr
888 -def copr_create_module_post(copr):
889 form = forms.CreateModuleForm(copr=copr, csrf_enabled=False)
890 args = [copr, form]
891 if "add_profile" in flask.request.values:
892 return add_profile(*args)
893 if "build_module" in flask.request.values:
894 return build_module(*args)
895
904
907 if not form.validate_on_submit():
908
909 for i in range(2, len(form.profile_names)):
910 form.profile_pkgs.append_entry()
911 return render_create_module(copr, form, profiles=len(form.profile_names))
912
913 summary = "Module from Copr repository: {}".format(copr.full_name)
914 generator = ModulemdGenerator(str(copr.name), summary=summary, config=app.config)
915 generator.add_filter(form.filter.data)
916 generator.add_api(form.api.data)
917 generator.add_profiles(enumerate(zip(form.profile_names.data, form.profile_pkgs.data)))
918 generator.add_components(form.packages.data, form.filter.data, form.builds.data)
919 yaml = generator.generate()
920
921 facade = None
922 try:
923 facade = ModuleBuildFacade(flask.g.user, copr, yaml)
924 module = facade.submit_build()
925 db.session.commit()
926
927 flask.flash("Modulemd yaml file successfully generated and submitted to be build as {}"
928 .format(module.nsv), "success")
929 return flask.redirect(url_for_copr_details(copr))
930
931 except ValidationError as ex:
932 flask.flash(ex.message, "error")
933 return render_create_module(copr, form, len(form.profile_names))
934
935 except sqlalchemy.exc.IntegrityError:
936 flask.flash("Module {}-{}-{} already exists".format(
937 facade.modulemd.name, facade.modulemd.stream, facade.modulemd.version), "error")
938 db.session.rollback()
939 return render_create_module(copr, form, len(form.profile_names))
940
941
942 @coprs_ns.route("/<username>/<coprname>/module/<id>")
943 @coprs_ns.route("/g/<group_name>/<coprname>/module/<id>")
944 @req_with_copr
945 -def copr_module(copr, id):
963
964
965 @coprs_ns.route("/<username>/<coprname>/module/<id>/raw")
966 @coprs_ns.route("/g/<group_name>/<coprname>/module/<id>/raw")
967 @req_with_copr
968 -def copr_module_raw(copr, id):
975