1
2
3 import os
4 import time
5 import fnmatch
6 import re
7 import uuid
8 import subprocess
9 from six.moves.urllib.parse import urljoin
10
11 import flask
12 from flask import render_template, url_for, stream_with_context
13 import platform
14 import smtplib
15 import sqlalchemy
16 import modulemd
17 from email.mime.text import MIMEText
18 from itertools import groupby
19
20 from pygments import highlight
21 from pygments.lexers import get_lexer_by_name
22 from pygments.formatters import HtmlFormatter
23
24 from coprs import app
25 from coprs import db
26 from coprs import rcp
27 from coprs import exceptions
28 from coprs import forms
29 from coprs import helpers
30 from coprs import models
31 from coprs.exceptions import ObjectNotFound
32 from coprs.logic.coprs_logic import CoprsLogic
33 from coprs.logic.packages_logic import PackagesLogic
34 from coprs.logic.stat_logic import CounterStatLogic
35 from coprs.logic.users_logic import UsersLogic
36 from coprs.logic.modules_logic import ModulesLogic
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
56
63
64
65 @coprs_ns.route("/", defaults={"page": 1})
66 @coprs_ns.route("/<int:page>/")
67 -def coprs_show(page=1):
85
86
87 @coprs_ns.route("/<username>/", defaults={"page": 1})
88 @coprs_ns.route("/<username>/<int:page>/")
89 -def coprs_by_user(username=None, page=1):
112
113
114 @coprs_ns.route("/fulltext/", defaults={"page": 1})
115 @coprs_ns.route("/fulltext/<int:page>/")
116 -def coprs_fulltext_search(page=1):
117 fulltext = flask.request.args.get("fulltext", "")
118 try:
119 query = coprs_logic.CoprsLogic.get_multiple_fulltext(fulltext)
120 except ValueError as e:
121 flask.flash(str(e), "error")
122 return flask.redirect(flask.request.referrer or
123 flask.url_for("coprs_ns.coprs_show"))
124
125 paginator = helpers.Paginator(query, query.count(), page,
126 additional_params={"fulltext": fulltext})
127
128 coprs = paginator.sliced_query
129 return render_template(
130 "coprs/show/fulltext.html",
131 coprs=coprs,
132 paginator=paginator,
133 fulltext=fulltext,
134 tasks_info=ComplexLogic.get_queues_size(),
135 )
136
137
138 @coprs_ns.route("/<username>/add/")
139 @login_required
140 -def copr_add(username):
144
145
146 @coprs_ns.route("/g/<group_name>/add/")
147 @login_required
148 -def group_copr_add(group_name):
154
155
156 @coprs_ns.route("/g/<group_name>/new/", methods=["POST"])
159 group = ComplexLogic.get_group_by_name_safe(group_name)
160 form = forms.CoprFormFactory.create_form_cls(group=group)()
161
162 if form.validate_on_submit():
163 try:
164 copr = coprs_logic.CoprsLogic.add(
165 flask.g.user,
166 name=form.name.data,
167 homepage=form.homepage.data,
168 contact=form.contact.data,
169 repos=form.repos.data.replace("\n", " "),
170 selected_chroots=form.selected_chroots,
171 description=form.description.data,
172 instructions=form.instructions.data,
173 disable_createrepo=form.disable_createrepo.data,
174 build_enable_net=form.build_enable_net.data,
175 unlisted_on_hp=form.unlisted_on_hp.data,
176 group=group,
177 persistent=form.persistent.data,
178 auto_prune=(form.auto_prune.data if flask.g.user.admin else True),
179 )
180 except (exceptions.DuplicateException, exceptions.NonAdminCannotCreatePersistentProject) as e:
181 flask.flash(str(e), "error")
182 return flask.render_template("coprs/group_add.html", form=form, group=group)
183
184 db.session.add(copr)
185 db.session.commit()
186 after_the_project_creation(copr, form)
187
188 return flask.redirect(url_for_copr_details(copr))
189 else:
190 return flask.render_template("coprs/group_add.html", form=form, group=group)
191
192
193 @coprs_ns.route("/<username>/new/", methods=["POST"])
194 @login_required
195 -def copr_new(username):
196 """
197 Receive information from the user on how to create its new copr
198 and create it accordingly.
199 """
200
201 form = forms.CoprFormFactory.create_form_cls()()
202 if form.validate_on_submit():
203 try:
204 copr = coprs_logic.CoprsLogic.add(
205 flask.g.user,
206 name=form.name.data,
207 homepage=form.homepage.data,
208 contact=form.contact.data,
209 repos=form.repos.data.replace("\n", " "),
210 selected_chroots=form.selected_chroots,
211 description=form.description.data,
212 instructions=form.instructions.data,
213 disable_createrepo=form.disable_createrepo.data,
214 build_enable_net=form.build_enable_net.data,
215 unlisted_on_hp=form.unlisted_on_hp.data,
216 persistent=form.persistent.data,
217 auto_prune=(form.auto_prune.data if flask.g.user.admin else True),
218 )
219 except (exceptions.DuplicateException, exceptions.NonAdminCannotCreatePersistentProject) as e:
220 flask.flash(str(e), "error")
221 return flask.render_template("coprs/add.html", form=form)
222
223 db.session.commit()
224 after_the_project_creation(copr, form)
225
226 return flask.redirect(url_for_copr_details(copr))
227 else:
228 return flask.render_template("coprs/add.html", form=form)
229
232 flask.flash("New project has been created successfully.", "success")
233 _check_rpmfusion(copr.repos)
234 if form.initial_pkgs.data:
235 pkgs = form.initial_pkgs.data.replace("\n", " ").split(" ")
236
237
238 bad_urls = []
239 for pkg in pkgs:
240 if not re.match("^.*\.src\.rpm$", pkg):
241 bad_urls.append(pkg)
242 flask.flash("Bad url: {0} (skipped)".format(pkg))
243 for bad_url in bad_urls:
244 pkgs.remove(bad_url)
245
246 if not pkgs:
247 flask.flash("No initial packages submitted")
248 else:
249
250 for pkg in pkgs:
251 builds_logic.BuildsLogic.add(
252 flask.g.user,
253 pkgs=pkg,
254 copr=copr,
255 enable_net=form.build_enable_net.data
256 )
257
258 db.session.commit()
259 flask.flash("Initial packages were successfully submitted "
260 "for building.")
261
262
263 @coprs_ns.route("/<username>/<coprname>/report-abuse")
264 @req_with_copr
265 @login_required
266 -def copr_report_abuse(copr):
268
269
270 @coprs_ns.route("/g/<group_name>/<coprname>/report-abuse")
271 @req_with_copr
272 @login_required
273 -def group_copr_report_abuse(copr):
275
280
281
282 @coprs_ns.route("/g/<group_name>/<coprname>/")
283 @req_with_copr
284 -def group_copr_detail(copr):
286
287
288 @coprs_ns.route("/<username>/<coprname>/")
289 @req_with_copr
290 -def copr_detail(copr):
294
297 repo_dl_stat = CounterStatLogic.get_copr_repo_dl_stat(copr)
298 form = forms.CoprLegalFlagForm()
299 repos_info = {}
300 for chroot in copr.active_chroots:
301
302
303
304
305
306 chroot_rpms_dl_stat_key = CHROOT_RPMS_DL_STAT_FMT.format(
307 copr_user=copr.user.name,
308 copr_project_name=copr.name,
309 copr_chroot=chroot.name,
310 )
311 chroot_rpms_dl_stat = TimedStatEvents.get_count(
312 rconnect=rcp.get_connection(),
313 name=chroot_rpms_dl_stat_key,
314 )
315
316 logoset = set()
317 logodir = app.static_folder + "/chroot_logodir"
318 for logo in os.listdir(logodir):
319
320 if fnmatch.fnmatch(logo, "*.png"):
321 logoset.add(logo.strip(".png"))
322
323 if chroot.name_release not in repos_info:
324 logo = None
325 if chroot.name_release in logoset:
326 logo = chroot.name_release + ".png"
327 elif chroot.os_release in logoset:
328 logo = chroot.os_release + ".png"
329
330 repos_info[chroot.name_release] = {
331 "name_release": chroot.name_release,
332 "name_release_human": chroot.name_release_human,
333 "os_release": chroot.os_release,
334 "os_version": chroot.os_version,
335 "logo": logo,
336 "arch_list": [chroot.arch],
337 "repo_file": "{}-{}.repo".format(copr.repo_id, chroot.name_release),
338 "dl_stat": repo_dl_stat[chroot.name_release],
339 "rpm_dl_stat": {
340 chroot.arch: chroot_rpms_dl_stat
341 }
342 }
343 else:
344 repos_info[chroot.name_release]["arch_list"].append(chroot.arch)
345 repos_info[chroot.name_release]["rpm_dl_stat"][chroot.arch] = chroot_rpms_dl_stat
346 repos_info_list = sorted(repos_info.values(), key=lambda rec: rec["name_release"])
347 builds = builds_logic.BuildsLogic.get_multiple_by_copr(copr=copr).limit(1).all()
348
349 return flask.render_template(
350 "coprs/detail/overview.html",
351 copr=copr,
352 user=flask.g.user,
353 form=form,
354 repo_dl_stat=repo_dl_stat,
355 repos_info_list=repos_info_list,
356 latest_build=builds[0] if len(builds) == 1 else None,
357 )
358
359
360 @coprs_ns.route("/<username>/<coprname>/permissions/")
361 @req_with_copr
362 -def copr_permissions(copr):
390
406
407
408 @coprs_ns.route("/g/<group_name>/<coprname>/webhooks/")
409 @login_required
410 @req_with_copr
411 -def group_copr_webhooks(copr):
413
414
415 @coprs_ns.route("/<username>/<coprname>/webhooks/")
416 @login_required
417 @req_with_copr
418 -def copr_webhooks(copr):
420
429
430
431 @coprs_ns.route("/g/<group_name>/<coprname>/edit/")
432 @login_required
433 @req_with_copr
434 -def group_copr_edit(copr, form=None):
436
437
438 @coprs_ns.route("/<username>/<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://fedorahosted.org/copr/wiki/UserDocs#WhatIcanbuildinCopr">What I can build in Copr</a>.')
448 flask.flash(message, "error")
449
479
480
481 @coprs_ns.route("/g/<group_name>/<coprname>/update/", methods=["POST"])
496
497
498 @coprs_ns.route("/<username>/<coprname>/update/", methods=["POST"])
499 @login_required
500 @req_with_copr
501 -def copr_update(copr):
509
510
511 @coprs_ns.route("/<username>/<coprname>/permissions_applier_change/",
512 methods=["POST"])
516 permission = coprs_logic.CoprPermissionsLogic.get(copr, flask.g.user).first()
517 applier_permissions_form = \
518 forms.PermissionsApplierFormFactory.create_form_cls(permission)()
519
520 if copr.user == flask.g.user:
521 flask.flash("Owner cannot request permissions for his own project.", "error")
522 elif applier_permissions_form.validate_on_submit():
523
524 if permission is not None:
525 old_builder = permission.copr_builder
526 old_admin = permission.copr_admin
527 else:
528 old_builder = 0
529 old_admin = 0
530 new_builder = applier_permissions_form.copr_builder.data
531 new_admin = applier_permissions_form.copr_admin.data
532 coprs_logic.CoprPermissionsLogic.update_permissions_by_applier(
533 flask.g.user, copr, permission, new_builder, new_admin)
534 db.session.commit()
535 flask.flash(
536 "Successfuly updated permissions for project '{0}'."
537 .format(copr.name))
538 admin_mails = [copr.user.mail]
539 for perm in copr.copr_permissions:
540
541 if perm.copr_admin == 2:
542 admin_mails.append(perm.user.mail)
543
544
545 if flask.current_app.config.get("SEND_EMAILS", False):
546 for mail in admin_mails:
547 msg = MIMEText(
548 "{6} is asking for these permissions:\n\n"
549 "Builder: {0} -> {1}\nAdmin: {2} -> {3}\n\n"
550 "Project: {4}\nOwner: {5}".format(
551 helpers.PermissionEnum(old_builder),
552 helpers.PermissionEnum(new_builder),
553 helpers.PermissionEnum(old_admin),
554 helpers.PermissionEnum(new_admin),
555 copr.name, copr.user.name, flask.g.user.name))
556
557 msg["Subject"] = "[Copr] {0}: {1} is asking permissons".format(copr.name, flask.g.user.name)
558 msg["From"] = "root@{0}".format(platform.node())
559 msg["To"] = mail
560 s = smtplib.SMTP("localhost")
561 s.sendmail("root@{0}".format(platform.node()), mail, msg.as_string())
562 s.quit()
563
564 return flask.redirect(flask.url_for("coprs_ns.copr_detail",
565 username=copr.user.name,
566 coprname=copr.name))
567
568
569 @coprs_ns.route("/<username>/<coprname>/update_permissions/", methods=["POST"])
573 permissions = copr.copr_permissions
574 permissions_form = forms.PermissionsFormFactory.create_form_cls(
575 permissions)()
576
577 if permissions_form.validate_on_submit():
578
579 try:
580
581
582 permissions.sort(
583 key=lambda x: -1 if x.user_id == flask.g.user.id else 1)
584 for perm in permissions:
585 old_builder = perm.copr_builder
586 old_admin = perm.copr_admin
587 new_builder = permissions_form[
588 "copr_builder_{0}".format(perm.user_id)].data
589 new_admin = permissions_form[
590 "copr_admin_{0}".format(perm.user_id)].data
591 coprs_logic.CoprPermissionsLogic.update_permissions(
592 flask.g.user, copr, perm, new_builder, new_admin)
593 if flask.current_app.config.get("SEND_EMAILS", False) and \
594 (old_builder is not new_builder or old_admin is not new_admin):
595
596 msg = MIMEText(
597 "Your permissions have changed:\n\n"
598 "Builder: {0} -> {1}\nAdmin: {2} -> {3}\n\n"
599 "Project: {4}\nOwner: {5}".format(
600 helpers.PermissionEnum(old_builder),
601 helpers.PermissionEnum(new_builder),
602 helpers.PermissionEnum(old_admin),
603 helpers.PermissionEnum(new_admin),
604 copr.name, copr.user.name))
605
606 msg["Subject"] = "[Copr] {0}: Your permissions have changed".format(copr.name)
607 msg["From"] = "root@{0}".format(platform.node())
608 msg["To"] = perm.user.mail
609 s = smtplib.SMTP("localhost")
610 s.sendmail("root@{0}".format(platform.node()), perm.user.mail, msg.as_string())
611 s.quit()
612
613
614 except exceptions.InsufficientRightsException as e:
615 db.session.rollback()
616 flask.flash(str(e), "error")
617 else:
618 db.session.commit()
619 flask.flash("Project permissions were updated successfully.", "success")
620
621 return flask.redirect(url_for_copr_details(copr))
622
623
624 @coprs_ns.route("/id/<copr_id>/createrepo/", methods=["POST"])
637
640 form = forms.CoprDeleteForm()
641 if form.validate_on_submit():
642
643 try:
644 ComplexLogic.delete_copr(copr)
645 except (exceptions.ActionInProgressException,
646 exceptions.InsufficientRightsException) as e:
647
648 db.session.rollback()
649 flask.flash(str(e), "error")
650 return flask.redirect(url_on_error)
651 else:
652 db.session.commit()
653 flask.flash("Project has been deleted successfully.")
654 return flask.redirect(url_on_success)
655 else:
656 return render_template("coprs/detail/settings/delete.html", form=form, copr=copr)
657
658
659 @coprs_ns.route("/<username>/<coprname>/delete/", methods=["GET", "POST"])
660 @login_required
661 @req_with_copr
662 -def copr_delete(copr):
669
670
671 @coprs_ns.route("/g/<group_name>/<coprname>/delete/", methods=["GET", "POST"])
683
684
685 @coprs_ns.route("/<username>/<coprname>/legal_flag/", methods=["POST"])
691
692
693 @coprs_ns.route("/g/<group_name>/<coprname>/legal_flag/", methods=["POST"])
699
702 form = forms.CoprLegalFlagForm()
703 legal_flag = models.LegalFlag(raise_message=form.comment.data,
704 raised_on=int(time.time()),
705 copr=copr,
706 reporter=flask.g.user)
707 db.session.add(legal_flag)
708 db.session.commit()
709 send_to = app.config["SEND_LEGAL_TO"] or ["root@localhost"]
710 hostname = platform.node()
711 navigate_to = "\nNavigate to http://{0}{1}".format(
712 hostname, flask.url_for("admin_ns.legal_flag"))
713 contact = "\nContact on owner is: {}".format(contact_info)
714 reported_by = "\nReported by {0} <{1}>".format(flask.g.user.name,
715 flask.g.user.mail)
716 try:
717 msg = MIMEText(
718 form.comment.data + navigate_to + contact + reported_by, "plain")
719 except UnicodeEncodeError:
720 msg = MIMEText(form.comment.data.encode(
721 "utf-8") + navigate_to + contact + reported_by, "plain", "utf-8")
722 msg["Subject"] = "Legal flag raised on {0}".format(copr.name)
723 msg["From"] = "root@{0}".format(hostname)
724 msg["To"] = ", ".join(send_to)
725 s = smtplib.SMTP("localhost")
726 s.sendmail("root@{0}".format(hostname), send_to, msg.as_string())
727 s.quit()
728 flask.flash("Admin has been noticed about your report"
729 " and will investigate the project shortly.")
730 return flask.redirect(url_for_copr_details(copr))
731
732
733 @coprs_ns.route("/<username>/<coprname>/repo/<name_release>/", defaults={"repofile": None})
734 @coprs_ns.route("/<username>/<coprname>/repo/<name_release>/<repofile>")
735 -def generate_repo_file(username, coprname, name_release, repofile):
750
751
752 @coprs_ns.route("/g/<group_name>/<coprname>/repo/<name_release>/", defaults={"repofile": None})
753 @coprs_ns.route("/g/<group_name>/<coprname>/repo/<name_release>/<repofile>")
754 @req_with_copr
755 -def group_generate_repo_file(copr, name_release, repofile):
763
766
767
768 if name_release in [c.name for c in copr.mock_chroots]:
769 chroot = [c for c in copr.mock_chroots if c.name == name_release][0]
770 kwargs = dict(coprname=copr.name, name_release=chroot.name_release)
771 if copr.is_a_group_project:
772 fixed_url = url_for("coprs_ns.group_generate_repo_file",
773 group_name=copr.group.name, **kwargs)
774 else:
775 fixed_url = url_for("coprs_ns.generate_repo_file",
776 username=copr.user.username, **kwargs)
777 return flask.redirect(fixed_url)
778
779 mock_chroot = coprs_logic.MockChrootsLogic.get_from_name(name_release, noarch=True).first()
780 if not mock_chroot:
781 raise ObjectNotFound("Chroot {} does not exist".format(name_release))
782
783 url = os.path.join(copr.repo_url, '')
784 repo_url = generate_repo_url(mock_chroot, url)
785 pubkey_url = urljoin(url, "pubkey.gpg")
786 response = flask.make_response(
787 flask.render_template("coprs/copr.repo", copr=copr, url=repo_url, pubkey_url=pubkey_url))
788 response.mimetype = "text/plain"
789 response.headers["Content-Disposition"] = \
790 "filename={0}.repo".format(copr.repo_name)
791 return response
792
793
794
795
796
797
798 @coprs_ns.route("/<username>/<coprname>/repo/modules/")
799 @coprs_ns.route("/@<group_name>/<coprname>/repo/modules/")
800 @coprs_ns.route("/g/<group_name>/<coprname>/repo/modules/")
801 @req_with_copr
802 -def generate_module_repo_file(copr):
805
807 url = os.path.join(copr.repo_url, '')
808 pubkey_url = urljoin(url, "pubkey.gpg")
809 response = flask.make_response(
810 flask.render_template("coprs/copr-modules.cfg", copr=copr, url=url, pubkey_url=pubkey_url))
811 response.mimetype = "text/plain"
812 response.headers["Content-Disposition"] = \
813 "filename={0}.cfg".format(copr.repo_name)
814 return response
815
816
817
818 @coprs_ns.route("/<username>/<coprname>/rpm/<name_release>/<rpmfile>")
819 -def copr_repo_rpm_file(username, coprname, name_release, rpmfile):
820 try:
821 packages_dir = os.path.join(app.config["DATA_DIR"], "repo-rpm-packages")
822 with open(os.path.join(packages_dir, rpmfile), "rb") as rpm:
823 response = flask.make_response(rpm.read())
824 response.mimetype = "application/x-rpm"
825 response.headers["Content-Disposition"] = \
826 "filename={0}".format(rpmfile)
827 return response
828 except IOError:
829 return flask.render_template("404.html")
830
847
848
849 @coprs_ns.route("/<username>/<coprname>/monitor/")
850 @coprs_ns.route("/<username>/<coprname>/monitor/<detailed>")
851 @req_with_copr
852 -def copr_build_monitor(copr, detailed=False):
854
855
856 @coprs_ns.route("/g/<group_name>/<coprname>/monitor/")
857 @coprs_ns.route("/g/<group_name>/<coprname>/monitor/<detailed>")
858 @req_with_copr
859 -def group_copr_build_monitor(copr, detailed=False):
861
862
863 @coprs_ns.route("/<username>/<coprname>/fork/")
864 @coprs_ns.route("/g/<group_name>/<coprname>/fork/")
865 @login_required
866 @req_with_copr
867 -def copr_fork(copr):
870
873 return flask.render_template("coprs/fork.html", copr=copr, form=form, confirm=confirm)
874
875
876 @coprs_ns.route("/<username>/<coprname>/fork/", methods=["POST"])
877 @coprs_ns.route("/g/<group_name>/<coprname>/fork/", methods=["POST"])
878 @login_required
879 @req_with_copr
880 -def copr_fork_post(copr):
881 form = forms.CoprForkFormFactory.create_form_cls(copr=copr, user=flask.g.user, groups=flask.g.user.user_groups)()
882 if form.validate_on_submit():
883 dstgroup = ([g for g in flask.g.user.user_groups if g.at_name == form.owner.data] or [None])[0]
884 if flask.g.user.name != form.owner.data and not dstgroup:
885 return generic_error("There is no such group: {}".format(form.owner.data))
886
887 fcopr, created = ComplexLogic.fork_copr(copr, flask.g.user, dstname=form.name.data, dstgroup=dstgroup)
888 if created:
889 msg = ("Forking project {} for you into {}. Please be aware that it may take a few minutes "
890 "to duplicate a backend data.".format(copr.full_name, fcopr.full_name))
891 elif not created and form.confirm.data == True:
892 msg = ("Updating packages in {} from {}. Please be aware that it may take a few minutes "
893 "to duplicate a backend data.".format(copr.full_name, fcopr.full_name))
894 else:
895 return render_copr_fork(copr, form, confirm=True)
896
897 db.session.commit()
898 flask.flash(msg)
899
900 return flask.redirect(url_for_copr_details(fcopr))
901 return render_copr_fork(copr, form)
902
903
904 @coprs_ns.route("/update_search_index/", methods=["POST"])
906 subprocess.call(['/usr/share/copr/coprs_frontend/manage.py', 'update_indexes_quick', '1'])
907 return "OK"
908
909
910 @coprs_ns.route("/<username>/<coprname>/modules/")
911 @coprs_ns.route("/g/<group_name>/<coprname>/modules/")
912 @req_with_copr
913 -def copr_modules(copr):
915
920
921
922 @coprs_ns.route("/<username>/<coprname>/create_module/")
923 @coprs_ns.route("/g/<group_name>/<coprname>/create_module/")
924 @login_required
925 @req_with_copr
926 -def copr_create_module(copr):
929
938
939
940 @coprs_ns.route("/<username>/<coprname>/create_module/", methods=["POST"])
941 @coprs_ns.route("/g/<group_name>/<coprname>/create_module/", methods=["POST"])
942 @login_required
943 @req_with_copr
944 -def copr_create_module_post(copr):
945 form = forms.CreateModuleForm(copr=copr, csrf_enabled=False)
946 args = [copr, form]
947 if "add_profile" in flask.request.values:
948 return add_profile(*args)
949 if "build_module" in flask.request.values:
950 return build_module(*args)
951
960
963 if not form.validate_on_submit():
964
965 for i in range(2, len(form.profile_names)):
966 form.profile_pkgs.append_entry()
967 return render_create_module(copr, form, profiles=len(form.profile_names))
968
969 mmd = modulemd.ModuleMetadata()
970 mmd.name = str(copr.name)
971 mmd.stream = str(form.stream.data)
972 mmd.version = form.version.data
973 mmd.summary = "Module from Copr repository: {}".format(copr.full_name)
974
975 for package in form.filter.data:
976 mmd.filter.add_rpm(str(package))
977
978 for package in form.api.data:
979 mmd.api.add_rpm(str(package))
980
981 for i, values in enumerate(zip(form.profile_names.data, form.profile_pkgs.data)):
982 name, packages = values
983 mmd.profiles[name] = modulemd.profile.ModuleProfile()
984 for package in packages:
985 mmd.profiles[name].add_rpm(str(package))
986
987 module = ModulesLogic.add(flask.g.user, copr, ModulesLogic.from_modulemd(mmd.dumps()))
988 db.session.flush()
989 actions_logic.ActionsLogic.send_build_module(flask.g.user, copr, module)
990 db.session.commit()
991 flask.flash("Modulemd yaml file successfully generated and submitted to be build", "success")
992 return flask.redirect(url_for_copr_details(copr))
993
994
995 @coprs_ns.route("/<username>/<coprname>/module/<id>")
996 @coprs_ns.route("/g/<group_name>/<coprname>/module/<id>")
997 @req_with_copr
998 -def copr_module(copr, id):
999 module = ModulesLogic.get(id).first()
1000 formatter = HtmlFormatter(style="autumn", linenos=False, noclasses=True)
1001 pretty_yaml = highlight(module.yaml, get_lexer_by_name("YAML"), formatter)
1002 return flask.render_template("coprs/detail/module.html", copr=copr, module=module, yaml=pretty_yaml)
1003
1004
1005 @coprs_ns.route("/<username>/<coprname>/module/<id>/raw")
1006 @coprs_ns.route("/g/<group_name>/<coprname>/module/<id>/raw")
1007 @req_with_copr
1008 -def copr_module_raw(copr, id):
1009 module = ModulesLogic.get(id).first()
1010 response = flask.make_response(module.yaml)
1011 response.mimetype = "text/plain"
1012 response.headers["Content-Disposition"] = \
1013 "filename={}.yaml".format("-".join([str(module.id), module.name, module.stream, str(module.version)]))
1014 return response
1015