plugins.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2014-2017 - Copyright Red Hat Inc
  4. Authors:
  5. Pierre-Yves Chibon <pingou@pingoured.fr>
  6. Farhaan Bukhsh <farhaan.bukhsh@gmail.com>
  7. """
  8. # pylint: disable=too-many-branches
  9. from __future__ import unicode_literals, absolute_import
  10. import logging
  11. import flask
  12. from flask import Markup
  13. from sqlalchemy.exc import SQLAlchemyError
  14. import pagure.exceptions
  15. import pagure.forms
  16. import pagure.lib.plugins
  17. from pagure.exceptions import FileNotFoundException
  18. from pagure.ui import UI_NS
  19. from pagure.utils import login_required
  20. from pagure.decorators import is_repo_admin
  21. _log = logging.getLogger(__name__)
  22. @UI_NS.route("/<repo>/settings/<plugin>/", methods=("GET", "POST"))
  23. @UI_NS.route("/<repo>/settings/<plugin>", methods=("GET", "POST"))
  24. @UI_NS.route("/<namespace>/<repo>/settings/<plugin>/", methods=("GET", "POST"))
  25. @UI_NS.route("/<namespace>/<repo>/settings/<plugin>", methods=("GET", "POST"))
  26. @UI_NS.route("/<repo>/settings/<plugin>/<int:full>/", methods=("GET", "POST"))
  27. @UI_NS.route("/<repo>/settings/<plugin>/<int:full>", methods=("GET", "POST"))
  28. @UI_NS.route(
  29. "/<namespace>/<repo>/settings/<plugin>/<int:full>/",
  30. methods=("GET", "POST"),
  31. )
  32. @UI_NS.route(
  33. "/<namespace>/<repo>/settings/<plugin>/<int:full>", methods=("GET", "POST")
  34. )
  35. @UI_NS.route(
  36. "/fork/<username>/<repo>/settings/<plugin>/", methods=("GET", "POST")
  37. )
  38. @UI_NS.route(
  39. "/fork/<username>/<namespace>/<repo>/settings/<plugin>/",
  40. methods=("GET", "POST"),
  41. )
  42. @UI_NS.route(
  43. "/fork/<username>/<repo>/settings/<plugin>", methods=("GET", "POST")
  44. )
  45. @UI_NS.route(
  46. "/fork/<username>/<namespace>/<repo>/settings/<plugin>",
  47. methods=("GET", "POST"),
  48. )
  49. @UI_NS.route(
  50. "/fork/<username>/<repo>/settings/<plugin>/<int:full>/",
  51. methods=("GET", "POST"),
  52. )
  53. @UI_NS.route(
  54. "/fork/<username>/<namespace>/<repo>/settings/<plugin>/<int:full>/",
  55. methods=("GET", "POST"),
  56. )
  57. @UI_NS.route(
  58. "/fork/<username>/<repo>/settings/<plugin>/<int:full>",
  59. methods=("GET", "POST"),
  60. )
  61. @UI_NS.route(
  62. "/fork/<username>/<namespace>/<repo>/settings/<plugin>/<int:full>",
  63. methods=("GET", "POST"),
  64. )
  65. @login_required
  66. @is_repo_admin
  67. def view_plugin(repo, plugin, username=None, namespace=None, full=True):
  68. """ Presents the settings of the project.
  69. """
  70. repo = flask.g.repo
  71. # Private repos are not allowed to leak information outside so disabling CI
  72. # enables us to keep the repos totally discreate and prevents from leaking
  73. # information outside
  74. if repo.private and plugin == "Pagure CI":
  75. flask.abort(404, "Plugin disabled")
  76. if plugin in pagure.config.config.get("DISABLED_PLUGINS", []):
  77. flask.abort(404, "Plugin disabled")
  78. if plugin == "default":
  79. flask.abort(403, "This plugin cannot be changed")
  80. plugin = pagure.lib.plugins.get_plugin(plugin)
  81. fields = []
  82. new = True
  83. dbobj = plugin.db_object()
  84. if hasattr(repo, plugin.backref):
  85. dbobj = getattr(repo, plugin.backref)
  86. # There should always be only one, but let's double check
  87. if dbobj:
  88. new = False
  89. else:
  90. dbobj = plugin.db_object()
  91. form = plugin.form(obj=dbobj)
  92. for field in plugin.form_fields:
  93. fields.append(getattr(form, field))
  94. form_fields_readonly = []
  95. if hasattr(plugin, "form_fields_readonly"):
  96. form_fields_readonly = plugin.form_fields_readonly
  97. if form.validate_on_submit():
  98. form.populate_obj(obj=dbobj)
  99. if new:
  100. dbobj.project_id = repo.id
  101. flask.g.session.add(dbobj)
  102. try:
  103. flask.g.session.flush()
  104. except SQLAlchemyError: # pragma: no cover
  105. flask.g.session.rollback()
  106. _log.exception("Could not add plugin %s", plugin.name)
  107. message = Markup(
  108. "Could not add plugin,"
  109. ' please <a href="/about">contact an administrator</a>'
  110. )
  111. flask.flash(message % plugin.name)
  112. return flask.render_template(
  113. "plugin.html",
  114. select="settings",
  115. full=full,
  116. repo=repo,
  117. username=username,
  118. namespace=namespace,
  119. plugin=plugin,
  120. form=form,
  121. fields=fields,
  122. )
  123. # Compute the ci_hook active value in function
  124. # of the active PR and active commit values.
  125. if hasattr(form, "active_pr") and hasattr(form, "active_commit"):
  126. if form.active_pr.data or form.active_commit.data:
  127. form.active.data = True
  128. if form.active.data:
  129. try:
  130. # Set up the main script if necessary
  131. plugin.set_up(repo)
  132. # Install the plugin itself
  133. plugin.install(repo, dbobj)
  134. flask.flash("Hook %s activated" % plugin.name)
  135. except FileNotFoundException as err:
  136. flask.g.session.rollback()
  137. _log.exception(err)
  138. flask.abort(404, "No git repo found")
  139. else:
  140. try:
  141. plugin.remove(repo)
  142. except FileNotFoundException as err:
  143. flask.g.session.rollback()
  144. _log.exception(err)
  145. flask.abort(404, "No git repo found")
  146. flask.g.session.delete(dbobj)
  147. flask.flash("Hook %s deactivated" % plugin.name)
  148. flask.g.session.commit()
  149. return flask.redirect(
  150. flask.url_for(
  151. "ui_ns.view_settings",
  152. repo=repo.name,
  153. username=username,
  154. namespace=namespace,
  155. )
  156. )
  157. return flask.render_template(
  158. "plugin.html",
  159. select="settings",
  160. full=full,
  161. repo=repo,
  162. namespace=namespace,
  163. username=username,
  164. plugin=plugin,
  165. form=form,
  166. fields=fields,
  167. form_fields_readonly=form_fields_readonly,
  168. )