def new_user(): """ Create a new user. """ form = forms.NewUserForm() if form.validate_on_submit(): username = form.user.data if pagure.lib.search_user(SESSION, username=username): flask.flash('Username already taken.', 'error') return flask.redirect(flask.request.url) email = form.email_address.data if pagure.lib.search_user(SESSION, email=email): flask.flash('Email address already taken.', 'error') return flask.redirect(flask.request.url) form.password.data = generate_hashed_value(form.password.data) token = pagure.lib.login.id_generator(40) user = model.User() user.token = token form.populate_obj(obj=user) user.default_email = form.email_address.data SESSION.add(user) SESSION.flush() emails = [email.email for email in user.emails] if form.email_address.data not in emails: useremail = model.UserEmail( user_id=user.id, email=form.email_address.data) SESSION.add(useremail) SESSION.flush() try: SESSION.commit() send_confirmation_email(user) flask.flash( 'User created, please check your email to activate the ' 'account') except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() flask.flash('Could not create user.') APP.logger.debug('Could not create user.') APP.logger.exception(err) return flask.redirect(flask.url_for('auth_login')) return flask.render_template( 'login/user_new.html', form=form, )
def new_user(): """ Create a new user. """ form = forms.NewUserForm() if form.validate_on_submit(): username = form.user.data if pagure.lib.search_user(SESSION, username=username): flask.flash("Username already taken.", "error") return flask.redirect(flask.request.url) email = form.email_address.data if pagure.lib.search_user(SESSION, email=email): flask.flash("Email address already taken.", "error") return flask.redirect(flask.request.url) password = "******" % (form.password.data, APP.config.get("PASSWORD_SEED", None)) form.password.data = hashlib.sha512(password).hexdigest() token = pagure.lib.login.id_generator(40) user = model.User() user.token = token form.populate_obj(obj=user) user.default_email = form.email_address.data SESSION.add(user) SESSION.flush() emails = [email.email for email in user.emails] if form.email_address.data not in emails: useremail = model.UserEmail(user_id=user.id, email=form.email_address.data) SESSION.add(useremail) SESSION.flush() try: SESSION.flush() send_confirmation_email(user) flask.flash("User created, please check your email to activate the " "account") except SQLAlchemyError as err: SESSION.rollback() flask.flash("Could not create user.") APP.logger.debug("Could not create user.") APP.logger.exception(err) SESSION.commit() return flask.redirect(flask.url_for("auth_login")) return flask.render_template("login/user_new.html", form=form)
def api_new_issue(repo, username=None): """ Create a new issue ------------------ Open a new issue on a project. :: POST /api/0/<repo>/new_issue :: POST /api/0/fork/<username>/<repo>/new_issue Input ^^^^^ +--------------+----------+--------------+-----------------------------+ | Key | Type | Optionality | Description | +==============+==========+==============+=============================+ | ``title`` | string | Mandatory | The title of the issue | +--------------+----------+--------------+-----------------------------+ | ``content`` | string | Mandatory | | The description of the | | | | | issue | +--------------+----------+--------------+-----------------------------+ | ``private`` | boolean | Optional | | Include this key if | | | | | you want a private issue | | | | | to be created | +--------------+----------+--------------+-----------------------------+ Sample response ^^^^^^^^^^^^^^^ :: { "message": "Issue created" } """ repo = pagure.lib.get_project(SESSION, repo, user=username) output = {} if repo is None: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT) if not repo.settings.get('issue_tracker', True): raise pagure.exceptions.APIError( 404, error_code=APIERROR.ETRACKERDISABLED) if repo != flask.g.token.project: raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK) form = pagure.forms.IssueFormSimplied(csrf_enabled=False) if form.validate_on_submit(): title = form.title.data content = form.issue_content.data private = str(form.private.data).lower() in ['true', '1'] try: issue = pagure.lib.new_issue( SESSION, repo=repo, title=title, content=content, private=private, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.flush() # If there is a file attached, attach it. filestream = flask.request.files.get('filestream') if filestream and '<!!image>' in issue.content: new_filename = pagure.lib.git.add_file_to_git( repo=repo, issue=issue, ticketfolder=APP.config['TICKETS_FOLDER'], user=flask.g.fas_user, filename=filestream.filename, filestream=filestream.stream, ) # Replace the <!!image> tag in the comment with the link # to the actual image filelocation = flask.url_for( 'view_issue_raw_file', repo=repo.name, username=username, filename=new_filename, ) new_filename = new_filename.split('-', 1)[1] url = '[![%s](%s)](%s)' % ( new_filename, filelocation, filelocation) issue.content = issue.content.replace('<!!image>', url) SESSION.add(issue) SESSION.flush() SESSION.commit() output['message'] = 'Issue created' except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() APP.logger.exception(err) raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) else: raise pagure.exceptions.APIError(400, error_code=APIERROR.EINVALIDREQ) jsonout = flask.jsonify(output) return jsonout
def view_plugin(repo, plugin, username=None, full=True): """ Presents the settings of the project. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') if not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to change the settings for this project') if plugin in APP.config.get('DISABLED_PLUGINS', []): flask.abort(404, 'Plugin disabled') plugin = get_plugin(plugin) fields = [] new = True dbobj = plugin.db_object() if hasattr(repo, plugin.backref): dbobj = getattr(repo, plugin.backref) # There should always be only one, but let's double check if dbobj and len(dbobj) > 0: dbobj = dbobj[0] new = False else: dbobj = plugin.db_object() form = plugin.form(obj=dbobj) for field in plugin.form_fields: fields.append(getattr(form, field)) if form.validate_on_submit(): form.populate_obj(obj=dbobj) if new: dbobj.project_id = repo.id SESSION.add(dbobj) try: SESSION.flush() except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() APP.logger.debug('Could not add plugin %s', plugin.name) APP.logger.exception(err) flask.flash( 'Could not add plugin %s, please contact an admin' % plugin.name) return flask.render_template( 'plugin.html', select='settings', full=full, repo=repo, username=username, plugin=plugin, form=form, fields=fields) if form.active.data: # Set up the main script if necessary plugin.set_up(repo) # Install the plugin itself try: plugin.install(repo, dbobj) flask.flash('Hook %s activated' % plugin.name) except FileNotFoundException as err: pagure.APP.logger.exception(err) flask.abort(404, 'No git repo found') else: try: plugin.remove(repo) flask.flash('Hook %s inactived' % plugin.name) except FileNotFoundException as err: pagure.APP.logger.exception(err) flask.abort(404, 'No git repo found') SESSION.commit() return flask.redirect(flask.url_for( 'view_settings', repo=repo.name, username=username)) return flask.render_template( 'plugin.html', select='settings', full=full, repo=repo, username=username, plugin=plugin, form=form, fields=fields)
def api_new_issue(repo, username=None): """ Create a new issue ------------------ Open a new issue on a project. :: POST /api/0/<repo>/new_issue :: POST /api/0/fork/<username>/<repo>/new_issue Input ^^^^^ +--------------+----------+--------------+-----------------------------+ | Key | Type | Optionality | Description | +==============+==========+==============+=============================+ | ``title`` | string | Mandatory | The title of the issue | +--------------+----------+--------------+-----------------------------+ | ``content`` | string | Mandatory | | The description of the | | | | | issue | +--------------+----------+--------------+-----------------------------+ | ``private`` | boolean | Optional | | Include this key if | | | | | you want a private issue | | | | | to be created | +--------------+----------+--------------+-----------------------------+ Sample response ^^^^^^^^^^^^^^^ :: { "message": "Issue created" } """ repo = pagure.lib.get_project(SESSION, repo, user=username) output = {} if repo is None: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT) if not repo.settings.get('issue_tracker', True): raise pagure.exceptions.APIError(404, error_code=APIERROR.ETRACKERDISABLED) if repo != flask.g.token.project: raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK) form = pagure.forms.IssueFormSimplied(csrf_enabled=False) if form.validate_on_submit(): title = form.title.data content = form.issue_content.data private = form.private.data try: issue = pagure.lib.new_issue( SESSION, repo=repo, title=title, content=content, private=private or False, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.flush() # If there is a file attached, attach it. filestream = flask.request.files.get('filestream') if filestream and '<!!image>' in issue.content: new_filename = pagure.lib.git.add_file_to_git( repo=repo, issue=issue, ticketfolder=APP.config['TICKETS_FOLDER'], user=flask.g.fas_user, filename=filestream.filename, filestream=filestream.stream, ) # Replace the <!!image> tag in the comment with the link # to the actual image filelocation = flask.url_for( 'view_issue_raw_file', repo=repo.name, username=username, filename=new_filename, ) new_filename = new_filename.split('-', 1)[1] url = '[![%s](%s)](%s)' % (new_filename, filelocation, filelocation) issue.content = issue.content.replace('<!!image>', url) SESSION.add(issue) SESSION.flush() SESSION.commit() output['message'] = 'Issue created' except SQLAlchemyError, err: # pragma: no cover SESSION.rollback() APP.logger.exception(err) raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR)
def view_plugin(repo, plugin, username=None, full=True): """ Presents the settings of the project. """ repo = pagure.lib.get_project(SESSION, repo, user=username) if not repo: flask.abort(404, 'Project not found') if not is_repo_admin(repo): flask.abort( 403, 'You are not allowed to change the settings for this project') if plugin in APP.config.get('DISABLED_PLUGINS', []): flask.abort(404, 'Plugin disabled') plugin = get_plugin(plugin) fields = [] new = True dbobj = plugin.db_object() if hasattr(repo, plugin.backref): dbobj = getattr(repo, plugin.backref) # There should always be only one, but let's double check if dbobj and len(dbobj) > 0: dbobj = dbobj[0] new = False else: dbobj = plugin.db_object() form = plugin.form(obj=dbobj) for field in plugin.form_fields: fields.append(getattr(form, field)) if form.validate_on_submit(): form.populate_obj(obj=dbobj) if new: dbobj.project_id = repo.id SESSION.add(dbobj) try: SESSION.flush() except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() APP.logger.debug('Could not add plugin %s', plugin.name) APP.logger.exception(err) flask.flash('Could not add plugin %s, please contact an admin' % plugin.name) return flask.render_template('plugin.html', select='settings', full=full, repo=repo, username=username, plugin=plugin, form=form, fields=fields) if form.active.data: # Set up the main script if necessary plugin.set_up(repo) # Install the plugin itself plugin.install(repo, dbobj) flask.flash('Hook %s activated' % plugin.name) else: plugin.remove(repo) flask.flash('Hook %s inactived' % plugin.name) SESSION.commit() return flask.redirect( flask.url_for('view_settings', repo=repo.name, username=username)) return flask.render_template('plugin.html', select='settings', full=full, repo=repo, username=username, plugin=plugin, form=form, fields=fields)
def view_plugin(repo, plugin, username=None, namespace=None, full=True): """ Presents the settings of the project. """ repo = flask.g.repo if not flask.g.repo_admin: flask.abort( 403, 'You are not allowed to change the settings for this project') # Private repos are not allowed to leak information outside so disabling CI # enables us to keep the repos totally discreate and prevents from leaking # information outside if repo.private and plugin == 'Pagure CI': flask.abort(404, 'Plugin disabled') if plugin in APP.config.get('DISABLED_PLUGINS', []): flask.abort(404, 'Plugin disabled') if plugin == 'default': flask.abort(403, 'This plugin cannot be changed') plugin = pagure.lib.plugins.get_plugin(plugin) fields = [] new = True dbobj = plugin.db_object() if hasattr(repo, plugin.backref): dbobj = getattr(repo, plugin.backref) # There should always be only one, but let's double check if dbobj: new = False else: dbobj = plugin.db_object() form = plugin.form(obj=dbobj) for field in plugin.form_fields: fields.append(getattr(form, field)) if form.validate_on_submit(): form.populate_obj(obj=dbobj) if new: dbobj.project_id = repo.id SESSION.add(dbobj) try: SESSION.flush() except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() _log.exception('Could not add plugin %s', plugin.name) flask.flash('Could not add plugin %s, please contact an admin' % plugin.name) return flask.render_template('plugin.html', select='settings', full=full, repo=repo, username=username, namespace=namespace, plugin=plugin, form=form, fields=fields) if form.active.data: # Set up the main script if necessary plugin.set_up(repo) # Install the plugin itself try: plugin.install(repo, dbobj) flask.flash('Hook %s activated' % plugin.name) except FileNotFoundException as err: _log.exception(err) flask.abort(404, 'No git repo found') else: try: plugin.remove(repo) flask.flash('Hook %s deactivated' % plugin.name) except FileNotFoundException as err: _log.exception(err) flask.abort(404, 'No git repo found') SESSION.commit() return flask.redirect( flask.url_for('view_settings', repo=repo.name, username=username, namespace=namespace)) return flask.render_template('plugin.html', select='settings', full=full, repo=repo, namespace=namespace, username=username, plugin=plugin, form=form, fields=fields)
def api_new_issue(repo, username=None): """ Create a new issue ------------------ This endpoint can be used to open an issue on a project :: /api/0/<repo>/new_issue /api/0/fork/<username>/<repo>/new_issue Accepts POST queries only. :arg title: The title of the issue/ticket to create :arg content: The content of the issue to create (ie the description of the problem) :arg private: A boolean specifying whether this issue is private or not Sample response: :: { "message": "Issue created" } """ repo = pagure.lib.get_project(SESSION, repo, user=username) output = {} if repo is None: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT) if not repo.settings.get('issue_tracker', True): raise pagure.exceptions.APIError( 404, error_code=APIERROR.ETRACKERDISABLED) if repo != flask.g.token.project: raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK) status = pagure.lib.get_issue_statuses(SESSION) form = pagure.forms.IssueForm(status=status, csrf_enabled=False) if form.validate_on_submit(): title = form.title.data content = form.issue_content.data private = form.private.data try: issue = pagure.lib.new_issue( SESSION, repo=repo, title=title, content=content, private=private or False, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.flush() # If there is a file attached, attach it. filestream = flask.request.files.get('filestream') if filestream and '<!!image>' in issue.content: new_filename = pagure.lib.git.add_file_to_git( repo=repo, issue=issue, ticketfolder=APP.config['TICKETS_FOLDER'], user=flask.g.fas_user, filename=filestream.filename, filestream=filestream.stream, ) # Replace the <!!image> tag in the comment with the link # to the actual image filelocation = flask.url_for( 'view_issue_raw_file', repo=repo.name, username=username, filename=new_filename, ) new_filename = new_filename.split('-', 1)[1] url = '[![%s](%s)](%s)' % ( new_filename, filelocation, filelocation) issue.content = issue.content.replace('<!!image>', url) SESSION.add(issue) SESSION.flush() SESSION.commit() output['message'] = 'Issue created' except SQLAlchemyError, err: # pragma: no cover SESSION.rollback() APP.logger.exception(err) raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR)
def api_new_issue(repo, username=None, namespace=None): """ Create a new issue ------------------ Open a new issue on a project. :: POST /api/0/<repo>/new_issue POST /api/0/<namespace>/<repo>/new_issue :: POST /api/0/fork/<username>/<repo>/new_issue POST /api/0/fork/<username>/<namespace>/<repo>/new_issue Input ^^^^^ +-------------------+--------+-------------+---------------------------+ | Key | Type | Optionality | Description | +===================+========+=============+===========================+ | ``title`` | string | Mandatory | The title of the issue | +-------------------+--------+-------------+---------------------------+ | ``issue_content`` | string | Mandatory | | The description of the | | | | | issue | +-------------------+--------+-------------+---------------------------+ | ``private`` | boolean| Optional | | Include this key if | | | | | you want a private issue| | | | | to be created | +-------------------+--------+-------------+---------------------------+ | ``priority`` | string | Optional | | The priority to set to | | | | | this ticket from the | | | | | list of priorities set | | | | | in the project | +-------------------+--------+-------------+---------------------------+ | ``milestone`` | string | Optional | | The milestone to assign | | | | | to this ticket from the | | | | | list of milestones set | | | | | in the project | +-------------------+--------+-------------+---------------------------+ | ``tag`` | string | Optional | | Comma separated list of | | | | | tags to link to this | | | | | ticket from the list of | | | | | tags in the project | +-------------------+--------+-------------+---------------------------+ | ``assignee`` | string | Optional | | The username of the user| | | | | to assign this ticket to| +-------------------+--------+-------------+---------------------------+ Sample response ^^^^^^^^^^^^^^^ :: { "issue": { "assignee": null, "blocks": [], "close_status": null, "closed_at": null, "comments": [], "content": "This issue needs attention", "custom_fields": [], "date_created": "1479458613", "depends": [], "id": 1, "milestone": null, "priority": null, "private": false, "status": "Open", "tags": [], "title": "test issue", "user": { "fullname": "PY C", "name": "pingou" } }, "message": "Issue created" } """ output = {} repo = _get_repo(repo, username, namespace) _check_issue_tracker(repo) _check_token(repo, project_token=False) user_obj = pagure.lib.get_user(SESSION, flask.g.fas_user.username) if not user_obj: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOUSER) form = pagure.forms.IssueFormSimplied(priorities=repo.priorities, milestones=repo.milestones, csrf_enabled=False) if form.validate_on_submit(): title = form.title.data content = form.issue_content.data milestone = form.milestone.data or None private = str(form.private.data).lower() in ['true', '1'] priority = form.priority.data or None assignee = flask.request.form.get('assignee', '').strip() or None tags = [ tag.strip() for tag in flask.request.form.get('tag', '').split(',') if tag.strip() ] try: issue = pagure.lib.new_issue( SESSION, repo=repo, title=title, content=content, private=private, assignee=assignee, milestone=milestone, priority=priority, tags=tags, user=flask.g.fas_user.username, ticketfolder=APP.config['TICKETS_FOLDER'], ) SESSION.flush() # If there is a file attached, attach it. filestream = flask.request.files.get('filestream') if filestream and '<!!image>' in issue.content: new_filename = pagure.lib.add_attachment( repo=repo, issue=issue, attachmentfolder=APP.config['ATTACHMENTS_FOLDER'], user=user_obj, filename=filestream.filename, filestream=filestream.stream, ) # Replace the <!!image> tag in the comment with the link # to the actual image filelocation = flask.url_for( 'view_issue_raw_file', repo=repo.name, username=username, filename=new_filename, ) new_filename = new_filename.split('-', 1)[1] url = '[![%s](%s)](%s)' % (new_filename, filelocation, filelocation) issue.content = issue.content.replace('<!!image>', url) SESSION.add(issue) SESSION.flush() SESSION.commit() output['message'] = 'Issue created' output['issue'] = issue.to_json(public=True) except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() APP.logger.exception(err) raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) else: raise pagure.exceptions.APIError(400, error_code=APIERROR.EINVALIDREQ, errors=form.errors) jsonout = flask.jsonify(output) return jsonout