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
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, ModulemdGenerator, MBSProxy
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):
84
85
86 @coprs_ns.route("/<username>/", defaults={"page": 1})
87 @coprs_ns.route("/<username>/<int:page>/")
88 -def coprs_by_user(username=None, page=1):
111
112
113 @coprs_ns.route("/fulltext/", defaults={"page": 1})
114 @coprs_ns.route("/fulltext/<int:page>/")
115 -def coprs_fulltext_search(page=1):
116 fulltext = flask.request.args.get("fulltext", "")
117 try:
118 query = coprs_logic.CoprsLogic.get_multiple_fulltext(fulltext)
119 except ValueError as e:
120 flask.flash(str(e), "error")
121 return flask.redirect(flask.request.referrer or
122 flask.url_for("coprs_ns.coprs_show"))
123
124 paginator = helpers.Paginator(query, query.count(), page,
125 additional_params={"fulltext": fulltext})
126
127 coprs = paginator.sliced_query
128 return render_template(
129 "coprs/show/fulltext.html",
130 coprs=coprs,
131 paginator=paginator,
132 fulltext=fulltext,
133 tasks_info=ComplexLogic.get_queues_size(),
134 )
135
136
137 @coprs_ns.route("/<username>/add/")
138 @login_required
139 -def copr_add(username):
143
144
145 @coprs_ns.route("/g/<group_name>/add/")
146 @login_required
147 -def group_copr_add(group_name):
153
154
155 @coprs_ns.route("/g/<group_name>/new/", methods=["POST"])
158 group = ComplexLogic.get_group_by_name_safe(group_name)
159 form = forms.CoprFormFactory.create_form_cls(group=group)()
160
161 if form.validate_on_submit():
162 try:
163 copr = coprs_logic.CoprsLogic.add(
164 flask.g.user,
165 name=form.name.data,
166 homepage=form.homepage.data,
167 contact=form.contact.data,
168 repos=form.repos.data.replace("\n", " "),
169 selected_chroots=form.selected_chroots,
170 description=form.description.data,
171 instructions=form.instructions.data,
172 disable_createrepo=form.disable_createrepo.data,
173 build_enable_net=form.build_enable_net.data,
174 unlisted_on_hp=form.unlisted_on_hp.data,
175 group=group,
176 persistent=form.persistent.data,
177 auto_prune=(form.auto_prune.data if flask.g.user.admin else True),
178 use_bootstrap_container=form.use_bootstrap_container.data,
179 follow_fedora_branching=form.follow_fedora_branching.data,
180 )
181 except (exceptions.DuplicateException, exceptions.NonAdminCannotCreatePersistentProject) as e:
182 flask.flash(str(e), "error")
183 return flask.render_template("coprs/group_add.html", form=form, group=group)
184
185 db.session.add(copr)
186 db.session.commit()
187 after_the_project_creation(copr, form)
188
189 return flask.redirect(url_for_copr_details(copr))
190 else:
191 return flask.render_template("coprs/group_add.html", form=form, group=group)
192
193
194 @coprs_ns.route("/<username>/new/", methods=["POST"])
195 @login_required
196 -def copr_new(username):
197 """
198 Receive information from the user on how to create its new copr
199 and create it accordingly.
200 """
201
202 form = forms.CoprFormFactory.create_form_cls()()
203 if form.validate_on_submit():
204 try:
205 copr = coprs_logic.CoprsLogic.add(
206 flask.g.user,
207 name=form.name.data,
208 homepage=form.homepage.data,
209 contact=form.contact.data,
210 repos=form.repos.data.replace("\n", " "),
211 selected_chroots=form.selected_chroots,
212 description=form.description.data,
213 instructions=form.instructions.data,
214 disable_createrepo=form.disable_createrepo.data,
215 build_enable_net=form.build_enable_net.data,
216 unlisted_on_hp=form.unlisted_on_hp.data,
217 persistent=form.persistent.data,
218 auto_prune=(form.auto_prune.data if flask.g.user.admin else True),
219 use_bootstrap_container=form.use_bootstrap_container.data,
220 follow_fedora_branching=form.follow_fedora_branching.data,
221 )
222 except (exceptions.DuplicateException, exceptions.NonAdminCannotCreatePersistentProject) as e:
223 flask.flash(str(e), "error")
224 return flask.render_template("coprs/add.html", form=form)
225
226 db.session.commit()
227 after_the_project_creation(copr, form)
228
229 return flask.redirect(url_for_copr_details(copr))
230 else:
231 return flask.render_template("coprs/add.html", form=form)
232
235 flask.flash("New project has been created successfully.", "success")
236 _check_rpmfusion(copr.repos)
237 if form.initial_pkgs.data:
238 pkgs = form.initial_pkgs.data.replace("\n", " ").split(" ")
239
240
241 bad_urls = []
242 for pkg in pkgs:
243 if not pkg.endswith(".src.rpm"):
244 bad_urls.append(pkg)
245 flask.flash("Bad url: {0} (skipped)".format(pkg))
246 for bad_url in bad_urls:
247 pkgs.remove(bad_url)
248
249 if not pkgs:
250 flask.flash("No initial packages submitted")
251 else:
252
253 for pkg in pkgs:
254 builds_logic.BuildsLogic.add(
255 flask.g.user,
256 pkgs=pkg,
257 srpm_url=pkg,
258 copr=copr,
259 enable_net=form.build_enable_net.data
260 )
261
262 db.session.commit()
263 flask.flash("Initial packages were successfully submitted "
264 "for building.")
265
266
267 @coprs_ns.route("/<username>/<coprname>/report-abuse")
268 @req_with_copr
269 @login_required
270 -def copr_report_abuse(copr):
272
273
274 @coprs_ns.route("/g/<group_name>/<coprname>/report-abuse")
275 @req_with_copr
276 @login_required
277 -def group_copr_report_abuse(copr):
279
284
285
286 @coprs_ns.route("/g/<group_name>/<coprname>/")
287 @req_with_copr
288 -def group_copr_detail(copr):
290
291
292 @coprs_ns.route("/<username>/<coprname>/")
293 @req_with_copr
294 -def copr_detail(copr):
298
301 repo_dl_stat = CounterStatLogic.get_copr_repo_dl_stat(copr)
302 form = forms.CoprLegalFlagForm()
303 repos_info = {}
304 for chroot in copr.active_chroots:
305
306
307
308
309
310 chroot_rpms_dl_stat_key = CHROOT_RPMS_DL_STAT_FMT.format(
311 copr_user=copr.user.name,
312 copr_project_name=copr.name,
313 copr_chroot=chroot.name,
314 )
315 chroot_rpms_dl_stat = TimedStatEvents.get_count(
316 rconnect=rcp.get_connection(),
317 name=chroot_rpms_dl_stat_key,
318 )
319
320 logoset = set()
321 logodir = app.static_folder + "/chroot_logodir"
322 for logo in os.listdir(logodir):
323
324 if fnmatch.fnmatch(logo, "*.png"):
325 logoset.add(logo.strip(".png"))
326
327 if chroot.name_release not in repos_info:
328 logo = None
329 if chroot.name_release in logoset:
330 logo = chroot.name_release + ".png"
331 elif chroot.os_release in logoset:
332 logo = chroot.os_release + ".png"
333
334 repos_info[chroot.name_release] = {
335 "name_release": chroot.name_release,
336 "name_release_human": chroot.name_release_human,
337 "os_release": chroot.os_release,
338 "os_version": chroot.os_version,
339 "logo": logo,
340 "arch_list": [chroot.arch],
341 "repo_file": "{}-{}.repo".format(copr.repo_id, chroot.name_release),
342 "dl_stat": repo_dl_stat[chroot.name_release],
343 "rpm_dl_stat": {
344 chroot.arch: chroot_rpms_dl_stat
345 }
346 }
347 else:
348 repos_info[chroot.name_release]["arch_list"].append(chroot.arch)
349 repos_info[chroot.name_release]["rpm_dl_stat"][chroot.arch] = chroot_rpms_dl_stat
350 repos_info_list = sorted(repos_info.values(), key=lambda rec: rec["name_release"])
351 builds = builds_logic.BuildsLogic.get_multiple_by_copr(copr=copr).limit(1).all()
352
353 return flask.render_template(
354 "coprs/detail/overview.html",
355 copr=copr,
356 user=flask.g.user,
357 form=form,
358 repo_dl_stat=repo_dl_stat,
359 repos_info_list=repos_info_list,
360 latest_build=builds[0] if len(builds) == 1 else None,
361 )
362
363
364 @coprs_ns.route("/<username>/<coprname>/permissions/")
365 @req_with_copr
366 -def copr_permissions(copr):
394
415
416
417 @coprs_ns.route("/g/<group_name>/<coprname>/webhooks/")
418 @login_required
419 @req_with_copr
420 -def group_copr_webhooks(copr):
422
423
424 @coprs_ns.route("/<username>/<coprname>/webhooks/")
425 @login_required
426 @req_with_copr
427 -def copr_webhooks(copr):
429
438
439
440 @coprs_ns.route("/g/<group_name>/<coprname>/edit/")
441 @login_required
442 @req_with_copr
443 -def group_copr_edit(copr, form=None):
445
446
447 @coprs_ns.route("/<username>/<coprname>/edit/")
448 @login_required
449 @req_with_copr
450 -def copr_edit(copr, form=None):
452
455 if "rpmfusion" in repos:
456 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>.')
457 flask.flash(message, "error")
458
490
491
492 @coprs_ns.route("/g/<group_name>/<coprname>/update/", methods=["POST"])
507
508
509 @coprs_ns.route("/<username>/<coprname>/update/", methods=["POST"])
510 @login_required
511 @req_with_copr
512 -def copr_update(copr):
520
521
522 @coprs_ns.route("/<username>/<coprname>/permissions_applier_change/",
523 methods=["POST"])
527 permission = coprs_logic.CoprPermissionsLogic.get(copr, flask.g.user).first()
528 applier_permissions_form = \
529 forms.PermissionsApplierFormFactory.create_form_cls(permission)()
530
531 if copr.user == flask.g.user:
532 flask.flash("Owner cannot request permissions for his own project.", "error")
533 elif applier_permissions_form.validate_on_submit():
534
535 if permission is not None:
536 old_builder = permission.copr_builder
537 old_admin = permission.copr_admin
538 else:
539 old_builder = 0
540 old_admin = 0
541 new_builder = applier_permissions_form.copr_builder.data
542 new_admin = applier_permissions_form.copr_admin.data
543 coprs_logic.CoprPermissionsLogic.update_permissions_by_applier(
544 flask.g.user, copr, permission, new_builder, new_admin)
545 db.session.commit()
546 flask.flash(
547 "Successfully updated permissions for project '{0}'."
548 .format(copr.name))
549 admin_mails = [copr.user.mail]
550 for perm in copr.copr_permissions:
551
552 if perm.copr_admin == 2:
553 admin_mails.append(perm.user.mail)
554
555
556 if flask.current_app.config.get("SEND_EMAILS", False):
557 for mail in admin_mails:
558 msg = MIMEText(
559 "{6} is asking for these permissions:\n\n"
560 "Builder: {0} -> {1}\nAdmin: {2} -> {3}\n\n"
561 "Project: {4}\nOwner: {5}".format(
562 helpers.PermissionEnum(old_builder),
563 helpers.PermissionEnum(new_builder),
564 helpers.PermissionEnum(old_admin),
565 helpers.PermissionEnum(new_admin),
566 copr.name, copr.user.name, flask.g.user.name))
567
568 msg["Subject"] = "[Copr] {0}: {1} is asking permissions".format(copr.name, flask.g.user.name)
569 msg["From"] = "root@{0}".format(platform.node())
570 msg["To"] = mail
571 s = smtplib.SMTP("localhost")
572 s.sendmail("root@{0}".format(platform.node()), mail, msg.as_string())
573 s.quit()
574
575 return flask.redirect(flask.url_for("coprs_ns.copr_detail",
576 username=copr.user.name,
577 coprname=copr.name))
578
579
580 @coprs_ns.route("/<username>/<coprname>/update_permissions/", methods=["POST"])
584 permissions = copr.copr_permissions
585 permissions_form = forms.PermissionsFormFactory.create_form_cls(
586 permissions)()
587
588 if permissions_form.validate_on_submit():
589
590 try:
591
592
593 permissions.sort(
594 key=lambda x: -1 if x.user_id == flask.g.user.id else 1)
595 for perm in permissions:
596 old_builder = perm.copr_builder
597 old_admin = perm.copr_admin
598 new_builder = permissions_form[
599 "copr_builder_{0}".format(perm.user_id)].data
600 new_admin = permissions_form[
601 "copr_admin_{0}".format(perm.user_id)].data
602 coprs_logic.CoprPermissionsLogic.update_permissions(
603 flask.g.user, copr, perm, new_builder, new_admin)
604 if flask.current_app.config.get("SEND_EMAILS", False) and \
605 (old_builder is not new_builder or old_admin is not new_admin):
606
607 msg = MIMEText(
608 "Your permissions have changed:\n\n"
609 "Builder: {0} -> {1}\nAdmin: {2} -> {3}\n\n"
610 "Project: {4}\nOwner: {5}".format(
611 helpers.PermissionEnum(old_builder),
612 helpers.PermissionEnum(new_builder),
613 helpers.PermissionEnum(old_admin),
614 helpers.PermissionEnum(new_admin),
615 copr.name, copr.user.name))
616
617 msg["Subject"] = "[Copr] {0}: Your permissions have changed".format(copr.name)
618 msg["From"] = "root@{0}".format(platform.node())
619 msg["To"] = perm.user.mail
620 s = smtplib.SMTP("localhost")
621 s.sendmail("root@{0}".format(platform.node()), perm.user.mail, msg.as_string())
622 s.quit()
623
624
625 except exceptions.InsufficientRightsException as e:
626 db.session.rollback()
627 flask.flash(str(e), "error")
628 else:
629 db.session.commit()
630 flask.flash("Project permissions were updated successfully.", "success")
631
632 return flask.redirect(url_for_copr_details(copr))
633
634
635 @coprs_ns.route("/id/<copr_id>/createrepo/", methods=["POST"])
652
655 form = forms.CoprDeleteForm()
656 if form.validate_on_submit():
657
658 try:
659 ComplexLogic.delete_copr(copr)
660 except (exceptions.ActionInProgressException,
661 exceptions.InsufficientRightsException) as e:
662
663 db.session.rollback()
664 flask.flash(str(e), "error")
665 return flask.redirect(url_on_error)
666 else:
667 db.session.commit()
668 flask.flash("Project has been deleted successfully.")
669 return flask.redirect(url_on_success)
670 else:
671 return render_template("coprs/detail/settings/delete.html", form=form, copr=copr)
672
673
674 @coprs_ns.route("/<username>/<coprname>/delete/", methods=["GET", "POST"])
675 @login_required
676 @req_with_copr
677 -def copr_delete(copr):
684
685
686 @coprs_ns.route("/g/<group_name>/<coprname>/delete/", methods=["GET", "POST"])
698
699
700 @coprs_ns.route("/<username>/<coprname>/legal_flag/", methods=["POST"])
706
707
708 @coprs_ns.route("/g/<group_name>/<coprname>/legal_flag/", methods=["POST"])
714
717 form = forms.CoprLegalFlagForm()
718 legal_flag = models.LegalFlag(raise_message=form.comment.data,
719 raised_on=int(time.time()),
720 copr=copr,
721 reporter=flask.g.user)
722 db.session.add(legal_flag)
723 db.session.commit()
724 send_to = app.config["SEND_LEGAL_TO"] or ["root@localhost"]
725 hostname = platform.node()
726 navigate_to = "\nNavigate to http://{0}{1}".format(
727 hostname, flask.url_for("admin_ns.legal_flag"))
728 contact = "\nContact on owner is: {}".format(contact_info)
729 reported_by = "\nReported by {0} <{1}>".format(flask.g.user.name,
730 flask.g.user.mail)
731 try:
732 msg = MIMEText(
733 form.comment.data + navigate_to + contact + reported_by, "plain")
734 except UnicodeEncodeError:
735 msg = MIMEText(form.comment.data.encode(
736 "utf-8") + navigate_to + contact + reported_by, "plain", "utf-8")
737 msg["Subject"] = "Legal flag raised on {0}".format(copr.name)
738 msg["From"] = "root@{0}".format(hostname)
739 msg["To"] = ", ".join(send_to)
740 s = smtplib.SMTP("localhost")
741 s.sendmail("root@{0}".format(hostname), send_to, msg.as_string())
742 s.quit()
743 flask.flash("Admin has been noticed about your report"
744 " and will investigate the project shortly.")
745 return flask.redirect(url_for_copr_details(copr))
746
747
748 @coprs_ns.route("/<username>/<coprname>/repo/<name_release>/", defaults={"repofile": None})
749 @coprs_ns.route("/<username>/<coprname>/repo/<name_release>/<repofile>")
750 -def generate_repo_file(username, coprname, name_release, repofile):
765
766
767 @coprs_ns.route("/g/<group_name>/<coprname>/repo/<name_release>/", defaults={"repofile": None})
768 @coprs_ns.route("/g/<group_name>/<coprname>/repo/<name_release>/<repofile>")
769 @req_with_copr
770 -def group_generate_repo_file(copr, name_release, repofile):
778
781
782
783 if name_release in [c.name for c in copr.mock_chroots]:
784 chroot = [c for c in copr.mock_chroots if c.name == name_release][0]
785 kwargs = dict(coprname=copr.name, name_release=chroot.name_release)
786 if copr.is_a_group_project:
787 fixed_url = url_for("coprs_ns.group_generate_repo_file",
788 group_name=copr.group.name, **kwargs)
789 else:
790 fixed_url = url_for("coprs_ns.generate_repo_file",
791 username=copr.user.username, **kwargs)
792 return flask.redirect(fixed_url)
793
794 mock_chroot = coprs_logic.MockChrootsLogic.get_from_name(name_release, noarch=True).first()
795 if not mock_chroot:
796 raise ObjectNotFound("Chroot {} does not exist".format(name_release))
797
798 url = os.path.join(copr.repo_url, '')
799 repo_url = generate_repo_url(mock_chroot, url)
800 pubkey_url = urljoin(url, "pubkey.gpg")
801 response = flask.make_response(
802 flask.render_template("coprs/copr.repo", copr=copr, url=repo_url, pubkey_url=pubkey_url))
803 response.mimetype = "text/plain"
804 response.headers["Content-Disposition"] = \
805 "filename={0}.repo".format(copr.repo_name)
806
807 name = REPO_DL_STAT_FMT.format(**{
808 'copr_user': copr.user.name,
809 'copr_project_name': copr.name,
810 'copr_name_release': name_release,
811 })
812 CounterStatLogic.incr(name=name, counter_type=CounterStatType.REPO_DL)
813 db.session.commit()
814
815 return response
816
817
818
819
820
821
822 @coprs_ns.route("/<username>/<coprname>/repo/modules/")
823 @coprs_ns.route("/@<group_name>/<coprname>/repo/modules/")
824 @coprs_ns.route("/g/<group_name>/<coprname>/repo/modules/")
825 @req_with_copr
826 -def generate_module_repo_file(copr):
829
831 url = os.path.join(copr.repo_url, '')
832 pubkey_url = urljoin(url, "pubkey.gpg")
833 response = flask.make_response(
834 flask.render_template("coprs/copr-modules.cfg", copr=copr, url=url, pubkey_url=pubkey_url))
835 response.mimetype = "text/plain"
836 response.headers["Content-Disposition"] = \
837 "filename={0}.cfg".format(copr.repo_name)
838 return response
839
840
841
842 @coprs_ns.route("/<username>/<coprname>/rpm/<name_release>/<rpmfile>")
843 -def copr_repo_rpm_file(username, coprname, name_release, rpmfile):
844 try:
845 packages_dir = os.path.join(app.config["DATA_DIR"], "repo-rpm-packages")
846 with open(os.path.join(packages_dir, rpmfile), "rb") as rpm:
847 response = flask.make_response(rpm.read())
848 response.mimetype = "application/x-rpm"
849 response.headers["Content-Disposition"] = \
850 "filename={0}".format(rpmfile)
851 return response
852 except IOError:
853 return flask.render_template("404.html")
854
871
872
873 @coprs_ns.route("/<username>/<coprname>/monitor/")
874 @coprs_ns.route("/<username>/<coprname>/monitor/<detailed>")
875 @req_with_copr
876 -def copr_build_monitor(copr, detailed=False):
878
879
880 @coprs_ns.route("/g/<group_name>/<coprname>/monitor/")
881 @coprs_ns.route("/g/<group_name>/<coprname>/monitor/<detailed>")
882 @req_with_copr
883 -def group_copr_build_monitor(copr, detailed=False):
885
886
887 @coprs_ns.route("/<username>/<coprname>/fork/")
888 @coprs_ns.route("/g/<group_name>/<coprname>/fork/")
889 @login_required
890 @req_with_copr
891 -def copr_fork(copr):
894
897 return flask.render_template("coprs/fork.html", copr=copr, form=form, confirm=confirm)
898
899
900 @coprs_ns.route("/<username>/<coprname>/fork/", methods=["POST"])
901 @coprs_ns.route("/g/<group_name>/<coprname>/fork/", methods=["POST"])
902 @login_required
903 @req_with_copr
904 -def copr_fork_post(copr):
905 form = forms.CoprForkFormFactory.create_form_cls(copr=copr, user=flask.g.user, groups=flask.g.user.user_groups)()
906 if form.validate_on_submit():
907 dstgroup = ([g for g in flask.g.user.user_groups if g.at_name == form.owner.data] or [None])[0]
908 if flask.g.user.name != form.owner.data and not dstgroup:
909 return generic_error("There is no such group: {}".format(form.owner.data))
910
911 fcopr, created = ComplexLogic.fork_copr(copr, flask.g.user, dstname=form.name.data, dstgroup=dstgroup)
912 if created:
913 msg = ("Forking project {} for you into {}. Please be aware that it may take a few minutes "
914 "to duplicate a backend data.".format(copr.full_name, fcopr.full_name))
915 elif not created and form.confirm.data == True:
916 msg = ("Updating packages in {} from {}. Please be aware that it may take a few minutes "
917 "to duplicate a backend data.".format(copr.full_name, fcopr.full_name))
918 else:
919 return render_copr_fork(copr, form, confirm=True)
920
921 db.session.commit()
922 flask.flash(msg)
923
924 return flask.redirect(url_for_copr_details(fcopr))
925 return render_copr_fork(copr, form)
926
927
928 @coprs_ns.route("/update_search_index/", methods=["POST"])
930 subprocess.call(['/usr/share/copr/coprs_frontend/manage.py', 'update_indexes_quick', '1'])
931 return "OK"
932
933
934 @coprs_ns.route("/<username>/<coprname>/modules/")
935 @coprs_ns.route("/g/<group_name>/<coprname>/modules/")
936 @req_with_copr
937 -def copr_modules(copr):
939
944
945
946 @coprs_ns.route("/<username>/<coprname>/create_module/")
947 @coprs_ns.route("/g/<group_name>/<coprname>/create_module/")
948 @login_required
949 @req_with_copr
950 -def copr_create_module(copr):
953
962
963
964 @coprs_ns.route("/<username>/<coprname>/create_module/", methods=["POST"])
965 @coprs_ns.route("/g/<group_name>/<coprname>/create_module/", methods=["POST"])
966 @login_required
967 @req_with_copr
968 -def copr_create_module_post(copr):
969 form = forms.CreateModuleForm(copr=copr, csrf_enabled=False)
970 args = [copr, form]
971 if "add_profile" in flask.request.values:
972 return add_profile(*args)
973 if "build_module" in flask.request.values:
974 return build_module(*args)
975
984
987 if not form.validate_on_submit():
988
989 for i in range(2, len(form.profile_names)):
990 form.profile_pkgs.append_entry()
991 return render_create_module(copr, form, profiles=len(form.profile_names))
992
993 summary = "Module from Copr repository: {}".format(copr.full_name)
994 generator = ModulemdGenerator(str(copr.name), str(form.stream.data),
995 form.version.data, summary, app.config)
996 generator.add_filter(form.filter.data)
997 generator.add_api(form.api.data)
998 generator.add_profiles(enumerate(zip(form.profile_names.data, form.profile_pkgs.data)))
999 generator.add_components(form.packages.data, form.filter.data, form.builds.data)
1000 generator.add_base_runtime()
1001 tmp = tempfile.mktemp()
1002 generator.dump(tmp)
1003
1004 proxy = MBSProxy(mbs_url=flask.current_app.config["MBS_URL"], user_name=flask.g.user.name)
1005 with open(tmp) as tmp_handle:
1006 response = proxy.build_module(copr.owner_name, copr.name, generator.nsv, tmp_handle)
1007 os.remove(tmp)
1008
1009 if response.failed:
1010 flask.flash(response.message, "error")
1011 return render_create_module(copr, form, len(form.profile_names))
1012 flask.flash("Modulemd yaml file successfully generated and submitted to be build", "success")
1013 return flask.redirect(url_for_copr_details(copr))
1014
1015
1016 @coprs_ns.route("/<username>/<coprname>/module/<id>")
1017 @coprs_ns.route("/g/<group_name>/<coprname>/module/<id>")
1018 @req_with_copr
1019 -def copr_module(copr, id):
1020 module = ModulesLogic.get(id).first()
1021 formatter = HtmlFormatter(style="autumn", linenos=False, noclasses=True)
1022 pretty_yaml = highlight(module.yaml, get_lexer_by_name("YAML"), formatter)
1023 return flask.render_template("coprs/detail/module.html", copr=copr, module=module, yaml=pretty_yaml)
1024
1025
1026 @coprs_ns.route("/<username>/<coprname>/module/<id>/raw")
1027 @coprs_ns.route("/g/<group_name>/<coprname>/module/<id>/raw")
1028 @req_with_copr
1029 -def copr_module_raw(copr, id):
1030 module = ModulesLogic.get(id).first()
1031 response = flask.make_response(module.yaml)
1032 response.mimetype = "text/plain"
1033 response.headers["Content-Disposition"] = \
1034 "filename={}.yaml".format("-".join([str(module.id), module.name, module.stream, str(module.version)]))
1035 return response
1036