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 copr=copr,
258 enable_net=form.build_enable_net.data
259 )
260
261 db.session.commit()
262 flask.flash("Initial packages were successfully submitted "
263 "for building.")
264
265
266 @coprs_ns.route("/<username>/<coprname>/report-abuse")
267 @req_with_copr
268 @login_required
269 -def copr_report_abuse(copr):
271
272
273 @coprs_ns.route("/g/<group_name>/<coprname>/report-abuse")
274 @req_with_copr
275 @login_required
276 -def group_copr_report_abuse(copr):
278
283
284
285 @coprs_ns.route("/g/<group_name>/<coprname>/")
286 @req_with_copr
287 -def group_copr_detail(copr):
289
290
291 @coprs_ns.route("/<username>/<coprname>/")
292 @req_with_copr
293 -def copr_detail(copr):
297
300 repo_dl_stat = CounterStatLogic.get_copr_repo_dl_stat(copr)
301 form = forms.CoprLegalFlagForm()
302 repos_info = {}
303 for chroot in copr.active_chroots:
304
305
306
307
308
309 chroot_rpms_dl_stat_key = CHROOT_RPMS_DL_STAT_FMT.format(
310 copr_user=copr.user.name,
311 copr_project_name=copr.name,
312 copr_chroot=chroot.name,
313 )
314 chroot_rpms_dl_stat = TimedStatEvents.get_count(
315 rconnect=rcp.get_connection(),
316 name=chroot_rpms_dl_stat_key,
317 )
318
319 logoset = set()
320 logodir = app.static_folder + "/chroot_logodir"
321 for logo in os.listdir(logodir):
322
323 if fnmatch.fnmatch(logo, "*.png"):
324 logoset.add(logo.strip(".png"))
325
326 if chroot.name_release not in repos_info:
327 logo = None
328 if chroot.name_release in logoset:
329 logo = chroot.name_release + ".png"
330 elif chroot.os_release in logoset:
331 logo = chroot.os_release + ".png"
332
333 repos_info[chroot.name_release] = {
334 "name_release": chroot.name_release,
335 "name_release_human": chroot.name_release_human,
336 "os_release": chroot.os_release,
337 "os_version": chroot.os_version,
338 "logo": logo,
339 "arch_list": [chroot.arch],
340 "repo_file": "{}-{}.repo".format(copr.repo_id, chroot.name_release),
341 "dl_stat": repo_dl_stat[chroot.name_release],
342 "rpm_dl_stat": {
343 chroot.arch: chroot_rpms_dl_stat
344 }
345 }
346 else:
347 repos_info[chroot.name_release]["arch_list"].append(chroot.arch)
348 repos_info[chroot.name_release]["rpm_dl_stat"][chroot.arch] = chroot_rpms_dl_stat
349 repos_info_list = sorted(repos_info.values(), key=lambda rec: rec["name_release"])
350 builds = builds_logic.BuildsLogic.get_multiple_by_copr(copr=copr).limit(1).all()
351
352 return flask.render_template(
353 "coprs/detail/overview.html",
354 copr=copr,
355 user=flask.g.user,
356 form=form,
357 repo_dl_stat=repo_dl_stat,
358 repos_info_list=repos_info_list,
359 latest_build=builds[0] if len(builds) == 1 else None,
360 )
361
362
363 @coprs_ns.route("/<username>/<coprname>/permissions/")
364 @req_with_copr
365 -def copr_permissions(copr):
393
414
415
416 @coprs_ns.route("/g/<group_name>/<coprname>/webhooks/")
417 @login_required
418 @req_with_copr
419 -def group_copr_webhooks(copr):
421
422
423 @coprs_ns.route("/<username>/<coprname>/webhooks/")
424 @login_required
425 @req_with_copr
426 -def copr_webhooks(copr):
428
437
438
439 @coprs_ns.route("/g/<group_name>/<coprname>/edit/")
440 @login_required
441 @req_with_copr
442 -def group_copr_edit(copr, form=None):
444
445
446 @coprs_ns.route("/<username>/<coprname>/edit/")
447 @login_required
448 @req_with_copr
449 -def copr_edit(copr, form=None):
451
454 if "rpmfusion" in repos:
455 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>.')
456 flask.flash(message, "error")
457
489
490
491 @coprs_ns.route("/g/<group_name>/<coprname>/update/", methods=["POST"])
506
507
508 @coprs_ns.route("/<username>/<coprname>/update/", methods=["POST"])
509 @login_required
510 @req_with_copr
511 -def copr_update(copr):
519
520
521 @coprs_ns.route("/<username>/<coprname>/permissions_applier_change/",
522 methods=["POST"])
526 permission = coprs_logic.CoprPermissionsLogic.get(copr, flask.g.user).first()
527 applier_permissions_form = \
528 forms.PermissionsApplierFormFactory.create_form_cls(permission)()
529
530 if copr.user == flask.g.user:
531 flask.flash("Owner cannot request permissions for his own project.", "error")
532 elif applier_permissions_form.validate_on_submit():
533
534 if permission is not None:
535 old_builder = permission.copr_builder
536 old_admin = permission.copr_admin
537 else:
538 old_builder = 0
539 old_admin = 0
540 new_builder = applier_permissions_form.copr_builder.data
541 new_admin = applier_permissions_form.copr_admin.data
542 coprs_logic.CoprPermissionsLogic.update_permissions_by_applier(
543 flask.g.user, copr, permission, new_builder, new_admin)
544 db.session.commit()
545 flask.flash(
546 "Successfully updated permissions for project '{0}'."
547 .format(copr.name))
548 admin_mails = [copr.user.mail]
549 for perm in copr.copr_permissions:
550
551 if perm.copr_admin == 2:
552 admin_mails.append(perm.user.mail)
553
554
555 if flask.current_app.config.get("SEND_EMAILS", False):
556 for mail in admin_mails:
557 msg = MIMEText(
558 "{6} is asking for these permissions:\n\n"
559 "Builder: {0} -> {1}\nAdmin: {2} -> {3}\n\n"
560 "Project: {4}\nOwner: {5}".format(
561 helpers.PermissionEnum(old_builder),
562 helpers.PermissionEnum(new_builder),
563 helpers.PermissionEnum(old_admin),
564 helpers.PermissionEnum(new_admin),
565 copr.name, copr.user.name, flask.g.user.name))
566
567 msg["Subject"] = "[Copr] {0}: {1} is asking permissions".format(copr.name, flask.g.user.name)
568 msg["From"] = "root@{0}".format(platform.node())
569 msg["To"] = mail
570 s = smtplib.SMTP("localhost")
571 s.sendmail("root@{0}".format(platform.node()), mail, msg.as_string())
572 s.quit()
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"])
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
606 msg = MIMEText(
607 "Your permissions have changed:\n\n"
608 "Builder: {0} -> {1}\nAdmin: {2} -> {3}\n\n"
609 "Project: {4}\nOwner: {5}".format(
610 helpers.PermissionEnum(old_builder),
611 helpers.PermissionEnum(new_builder),
612 helpers.PermissionEnum(old_admin),
613 helpers.PermissionEnum(new_admin),
614 copr.name, copr.user.name))
615
616 msg["Subject"] = "[Copr] {0}: Your permissions have changed".format(copr.name)
617 msg["From"] = "root@{0}".format(platform.node())
618 msg["To"] = perm.user.mail
619 s = smtplib.SMTP("localhost")
620 s.sendmail("root@{0}".format(platform.node()), perm.user.mail, msg.as_string())
621 s.quit()
622
623
624 except exceptions.InsufficientRightsException as e:
625 db.session.rollback()
626 flask.flash(str(e), "error")
627 else:
628 db.session.commit()
629 flask.flash("Project permissions were updated successfully.", "success")
630
631 return flask.redirect(url_for_copr_details(copr))
632
633
634 @coprs_ns.route("/id/<copr_id>/createrepo/", methods=["POST"])
651
654 form = forms.CoprDeleteForm()
655 if form.validate_on_submit():
656
657 try:
658 ComplexLogic.delete_copr(copr)
659 except (exceptions.ActionInProgressException,
660 exceptions.InsufficientRightsException) as e:
661
662 db.session.rollback()
663 flask.flash(str(e), "error")
664 return flask.redirect(url_on_error)
665 else:
666 db.session.commit()
667 flask.flash("Project has been deleted successfully.")
668 return flask.redirect(url_on_success)
669 else:
670 return render_template("coprs/detail/settings/delete.html", form=form, copr=copr)
671
672
673 @coprs_ns.route("/<username>/<coprname>/delete/", methods=["GET", "POST"])
674 @login_required
675 @req_with_copr
676 -def copr_delete(copr):
683
684
685 @coprs_ns.route("/g/<group_name>/<coprname>/delete/", methods=["GET", "POST"])
697
698
699 @coprs_ns.route("/<username>/<coprname>/legal_flag/", methods=["POST"])
705
706
707 @coprs_ns.route("/g/<group_name>/<coprname>/legal_flag/", methods=["POST"])
713
716 form = forms.CoprLegalFlagForm()
717 legal_flag = models.LegalFlag(raise_message=form.comment.data,
718 raised_on=int(time.time()),
719 copr=copr,
720 reporter=flask.g.user)
721 db.session.add(legal_flag)
722 db.session.commit()
723 send_to = app.config["SEND_LEGAL_TO"] or ["root@localhost"]
724 hostname = platform.node()
725 navigate_to = "\nNavigate to http://{0}{1}".format(
726 hostname, flask.url_for("admin_ns.legal_flag"))
727 contact = "\nContact on owner is: {}".format(contact_info)
728 reported_by = "\nReported by {0} <{1}>".format(flask.g.user.name,
729 flask.g.user.mail)
730 try:
731 msg = MIMEText(
732 form.comment.data + navigate_to + contact + reported_by, "plain")
733 except UnicodeEncodeError:
734 msg = MIMEText(form.comment.data.encode(
735 "utf-8") + navigate_to + contact + reported_by, "plain", "utf-8")
736 msg["Subject"] = "Legal flag raised on {0}".format(copr.name)
737 msg["From"] = "root@{0}".format(hostname)
738 msg["To"] = ", ".join(send_to)
739 s = smtplib.SMTP("localhost")
740 s.sendmail("root@{0}".format(hostname), send_to, msg.as_string())
741 s.quit()
742 flask.flash("Admin has been noticed about your report"
743 " and will investigate the project shortly.")
744 return flask.redirect(url_for_copr_details(copr))
745
746
747 @coprs_ns.route("/<username>/<coprname>/repo/<name_release>/", defaults={"repofile": None})
748 @coprs_ns.route("/<username>/<coprname>/repo/<name_release>/<repofile>")
749 -def generate_repo_file(username, coprname, name_release, repofile):
764
765
766 @coprs_ns.route("/g/<group_name>/<coprname>/repo/<name_release>/", defaults={"repofile": None})
767 @coprs_ns.route("/g/<group_name>/<coprname>/repo/<name_release>/<repofile>")
768 @req_with_copr
769 -def group_generate_repo_file(copr, name_release, repofile):
777
780
781
782 if name_release in [c.name for c in copr.mock_chroots]:
783 chroot = [c for c in copr.mock_chroots if c.name == name_release][0]
784 kwargs = dict(coprname=copr.name, name_release=chroot.name_release)
785 if copr.is_a_group_project:
786 fixed_url = url_for("coprs_ns.group_generate_repo_file",
787 group_name=copr.group.name, **kwargs)
788 else:
789 fixed_url = url_for("coprs_ns.generate_repo_file",
790 username=copr.user.username, **kwargs)
791 return flask.redirect(fixed_url)
792
793 mock_chroot = coprs_logic.MockChrootsLogic.get_from_name(name_release, noarch=True).first()
794 if not mock_chroot:
795 raise ObjectNotFound("Chroot {} does not exist".format(name_release))
796
797 url = os.path.join(copr.repo_url, '')
798 repo_url = generate_repo_url(mock_chroot, url)
799 pubkey_url = urljoin(url, "pubkey.gpg")
800 response = flask.make_response(
801 flask.render_template("coprs/copr.repo", copr=copr, url=repo_url, pubkey_url=pubkey_url))
802 response.mimetype = "text/plain"
803 response.headers["Content-Disposition"] = \
804 "filename={0}.repo".format(copr.repo_name)
805
806 name = REPO_DL_STAT_FMT.format(**{
807 'copr_user': copr.user.name,
808 'copr_project_name': copr.name,
809 'copr_name_release': name_release,
810 })
811 CounterStatLogic.incr(name=name, counter_type=CounterStatType.REPO_DL)
812 db.session.commit()
813
814 return response
815
816
817
818
819
820
821 @coprs_ns.route("/<username>/<coprname>/repo/modules/")
822 @coprs_ns.route("/@<group_name>/<coprname>/repo/modules/")
823 @coprs_ns.route("/g/<group_name>/<coprname>/repo/modules/")
824 @req_with_copr
825 -def generate_module_repo_file(copr):
828
830 url = os.path.join(copr.repo_url, '')
831 pubkey_url = urljoin(url, "pubkey.gpg")
832 response = flask.make_response(
833 flask.render_template("coprs/copr-modules.cfg", copr=copr, url=url, pubkey_url=pubkey_url))
834 response.mimetype = "text/plain"
835 response.headers["Content-Disposition"] = \
836 "filename={0}.cfg".format(copr.repo_name)
837 return response
838
839
840
841 @coprs_ns.route("/<username>/<coprname>/rpm/<name_release>/<rpmfile>")
842 -def copr_repo_rpm_file(username, coprname, name_release, rpmfile):
843 try:
844 packages_dir = os.path.join(app.config["DATA_DIR"], "repo-rpm-packages")
845 with open(os.path.join(packages_dir, rpmfile), "rb") as rpm:
846 response = flask.make_response(rpm.read())
847 response.mimetype = "application/x-rpm"
848 response.headers["Content-Disposition"] = \
849 "filename={0}".format(rpmfile)
850 return response
851 except IOError:
852 return flask.render_template("404.html")
853
870
871
872 @coprs_ns.route("/<username>/<coprname>/monitor/")
873 @coprs_ns.route("/<username>/<coprname>/monitor/<detailed>")
874 @req_with_copr
875 -def copr_build_monitor(copr, detailed=False):
877
878
879 @coprs_ns.route("/g/<group_name>/<coprname>/monitor/")
880 @coprs_ns.route("/g/<group_name>/<coprname>/monitor/<detailed>")
881 @req_with_copr
882 -def group_copr_build_monitor(copr, detailed=False):
884
885
886 @coprs_ns.route("/<username>/<coprname>/fork/")
887 @coprs_ns.route("/g/<group_name>/<coprname>/fork/")
888 @login_required
889 @req_with_copr
890 -def copr_fork(copr):
893
896 return flask.render_template("coprs/fork.html", copr=copr, form=form, confirm=confirm)
897
898
899 @coprs_ns.route("/<username>/<coprname>/fork/", methods=["POST"])
900 @coprs_ns.route("/g/<group_name>/<coprname>/fork/", methods=["POST"])
901 @login_required
902 @req_with_copr
903 -def copr_fork_post(copr):
904 form = forms.CoprForkFormFactory.create_form_cls(copr=copr, user=flask.g.user, groups=flask.g.user.user_groups)()
905 if form.validate_on_submit():
906 dstgroup = ([g for g in flask.g.user.user_groups if g.at_name == form.owner.data] or [None])[0]
907 if flask.g.user.name != form.owner.data and not dstgroup:
908 return generic_error("There is no such group: {}".format(form.owner.data))
909
910 fcopr, created = ComplexLogic.fork_copr(copr, flask.g.user, dstname=form.name.data, dstgroup=dstgroup)
911 if created:
912 msg = ("Forking project {} for you into {}. Please be aware that it may take a few minutes "
913 "to duplicate a backend data.".format(copr.full_name, fcopr.full_name))
914 elif not created and form.confirm.data == True:
915 msg = ("Updating packages in {} from {}. Please be aware that it may take a few minutes "
916 "to duplicate a backend data.".format(copr.full_name, fcopr.full_name))
917 else:
918 return render_copr_fork(copr, form, confirm=True)
919
920 db.session.commit()
921 flask.flash(msg)
922
923 return flask.redirect(url_for_copr_details(fcopr))
924 return render_copr_fork(copr, form)
925
926
927 @coprs_ns.route("/update_search_index/", methods=["POST"])
929 subprocess.call(['/usr/share/copr/coprs_frontend/manage.py', 'update_indexes_quick', '1'])
930 return "OK"
931
932
933 @coprs_ns.route("/<username>/<coprname>/modules/")
934 @coprs_ns.route("/g/<group_name>/<coprname>/modules/")
935 @req_with_copr
936 -def copr_modules(copr):
938
943
944
945 @coprs_ns.route("/<username>/<coprname>/create_module/")
946 @coprs_ns.route("/g/<group_name>/<coprname>/create_module/")
947 @login_required
948 @req_with_copr
949 -def copr_create_module(copr):
952
961
962
963 @coprs_ns.route("/<username>/<coprname>/create_module/", methods=["POST"])
964 @coprs_ns.route("/g/<group_name>/<coprname>/create_module/", methods=["POST"])
965 @login_required
966 @req_with_copr
967 -def copr_create_module_post(copr):
968 form = forms.CreateModuleForm(copr=copr, csrf_enabled=False)
969 args = [copr, form]
970 if "add_profile" in flask.request.values:
971 return add_profile(*args)
972 if "build_module" in flask.request.values:
973 return build_module(*args)
974
983
986 if not form.validate_on_submit():
987
988 for i in range(2, len(form.profile_names)):
989 form.profile_pkgs.append_entry()
990 return render_create_module(copr, form, profiles=len(form.profile_names))
991
992 summary = "Module from Copr repository: {}".format(copr.full_name)
993 generator = ModulemdGenerator(str(copr.name), str(form.stream.data),
994 form.version.data, summary, app.config)
995 generator.add_filter(form.filter.data)
996 generator.add_api(form.api.data)
997 generator.add_profiles(enumerate(zip(form.profile_names.data, form.profile_pkgs.data)))
998 generator.add_components(form.packages.data, form.filter.data, form.builds.data)
999 generator.add_base_runtime()
1000 tmp = tempfile.mktemp()
1001 generator.dump(tmp)
1002
1003 proxy = MBSProxy(mbs_url=flask.current_app.config["MBS_URL"], user_name=flask.g.user.name)
1004 with open(tmp) as tmp_handle:
1005 response = proxy.build_module(copr.owner_name, copr.name, generator.nsv, tmp_handle)
1006 os.remove(tmp)
1007
1008 if response.failed:
1009 flask.flash(response.message, "error")
1010 return render_create_module(copr, form, len(form.profile_names))
1011 flask.flash("Modulemd yaml file successfully generated and submitted to be build", "success")
1012 return flask.redirect(url_for_copr_details(copr))
1013
1014
1015 @coprs_ns.route("/<username>/<coprname>/module/<id>")
1016 @coprs_ns.route("/g/<group_name>/<coprname>/module/<id>")
1017 @req_with_copr
1018 -def copr_module(copr, id):
1019 module = ModulesLogic.get(id).first()
1020 formatter = HtmlFormatter(style="autumn", linenos=False, noclasses=True)
1021 pretty_yaml = highlight(module.yaml, get_lexer_by_name("YAML"), formatter)
1022 return flask.render_template("coprs/detail/module.html", copr=copr, module=module, yaml=pretty_yaml)
1023
1024
1025 @coprs_ns.route("/<username>/<coprname>/module/<id>/raw")
1026 @coprs_ns.route("/g/<group_name>/<coprname>/module/<id>/raw")
1027 @req_with_copr
1028 -def copr_module_raw(copr, id):
1029 module = ModulesLogic.get(id).first()
1030 response = flask.make_response(module.yaml)
1031 response.mimetype = "text/plain"
1032 response.headers["Content-Disposition"] = \
1033 "filename={}.yaml".format("-".join([str(module.id), module.name, module.stream, str(module.version)]))
1034 return response
1035