def choose_template(service_id, template_type='all'): templates = service_api_client.get_service_templates(service_id)['data'] letters_available = ('letter' in current_service['permissions'] and current_user.has_permissions('view_activity')) available_template_types = list( filter(None, ( 'email', 'sms', 'letter' if letters_available else None, ))) templates = [ template for template in templates if template['template_type'] in available_template_types ] has_multiple_template_types = len( {template['template_type'] for template in templates}) > 1 template_nav_items = [ (label, key, url_for('.choose_template', service_id=current_service['id'], template_type=key), '') for label, key in filter(None, [ ('All', 'all'), ('Text message', 'sms'), ('Email', 'email'), ('Letter', 'letter') if letters_available else None, ]) ] templates_on_page = [ template for template in templates if (template_type in ['all', template['template_type']] and template['template_type'] in available_template_types) ] if current_user.has_permissions('view_activity'): page_title = 'Templates' else: page_title = 'Choose a template' return render_template( 'views/templates/choose.html', page_title=page_title, templates=templates_on_page, show_search_box=(len(templates_on_page) > 7), show_template_nav=has_multiple_template_types and (len(templates) > 2), template_nav_items=template_nav_items, template_type=template_type, search_form=SearchTemplatesForm(), )
def decorated(*args, **kwargs): has_permissions = current_user.has_permissions(self.permissions) if has_permissions: return fn(*args, **kwargs) else: abort(403)
def update_category(challenge_category_id: str): update_dict = request.json if current_user.has_permissions(["admin"]): updated = update_challenge_category(challenge_category_id, update_dict) return jsonify(updated.to_dict()) else: raise BadPermissionException(error_code=19)
def add_release(body): # we must require scope which depends on XPI type xpi_type = _xpi_type(body["revision"], body["xpi_name"]) required_permission = f"{SCOPE_PREFIX}/add_release/xpi/{xpi_type}" if not current_user.has_permissions(required_permission): user_permissions = ", ".join(current_user.get_permissions()) abort(401, f"required permission: {required_permission}, user permissions: {user_permissions}") session = current_app.db.session xpi = XPI(name=body["xpi_name"], revision=body["xpi_revision"], version=body["xpi_version"]) # project name used in the TC routes and matches the repo name project = current_app.config.get("XPI_MANIFEST_REPO") release = XPIRelease(revision=body["revision"], xpi=xpi, build_number=body["build_number"], status="scheduled", xpi_type=xpi_type, project=project) try: common_input = {"build_number": release.build_number, "xpi_name": release.xpi_name, "revision": release.xpi_revision, "version": release.xpi_version} release.phases = generate_phases(release, common_input, verify_supported_flavors=False) session.add(release) session.commit() except UnsupportedFlavor as e: raise BadRequest(description=e.description) except (IntegrityError, TaskclusterRestFailure) as e: # Report back Taskcluster and SQL failures for better visibility of the # actual issue. Usually it happens when we cannot find the indexed # task or a duplicate release request accordingly. abort(400, str(e)) logger.info("New release of %s", release.name) notify_via_matrix("xpi", f"New release of {release.name}") return release.json, 201
def create_category(): insert_dict = request.json if current_user.has_permissions(["admin"]): inserted = insert_challenge_category(insert_dict) return jsonify(inserted.to_dict()) else: raise BadPermissionException(error_code=21)
def view_jobs(service_id): jobs = current_service.get_page_of_jobs(page=request.args.get('page')) prev_page = None if jobs.prev_page: prev_page = generate_previous_dict('main.view_jobs', service_id, jobs.current_page) next_page = None if jobs.next_page: next_page = generate_next_dict('main.view_jobs', service_id, jobs.current_page) scheduled_jobs = '' if not current_user.has_permissions( 'view_activity') and jobs.current_page == 1: scheduled_jobs = render_template( 'views/dashboard/_upcoming.html', hide_heading=True, ) return render_template( 'views/jobs/jobs.html', jobs=jobs, prev_page=prev_page, next_page=next_page, scheduled_jobs=scheduled_jobs, )
def schedule_phase(name, phase): session = current_app.db.session phase = session.query(XPIPhase).filter( XPIRelease.id == XPIPhase.release_id).filter( XPIRelease.name == name).filter( XPIPhase.name == phase).first_or_404() # we must require scope which depends on XPI type xpi_type = _xpi_type(phase.release.revision, phase.release.xpi_name) required_permission = f"{SCOPE_PREFIX}/schedule_phase/xpi/{xpi_type}/{phase.name}" if not current_user.has_permissions(required_permission): user_permissions = ", ".join(current_user.get_permissions()) abort( 401, f"required permission: {required_permission}, user permissions: {user_permissions}" ) phase = do_schedule_phase(session, phase) url = taskcluster_urls.ui(get_root_url(), f"/tasks/groups/{phase.task_id}") logger.info("Phase %s of %s started by %s. - %s", phase.name, phase.release.name, phase.completed_by, url) notify_via_matrix( "xpi", f"Phase {phase.name} of {phase.release.name} started by {phase.completed_by}. - {url}" ) return phase.json
def get_back_link(service_id, template_id, step_index): if get_help_argument(): # if we're on the check page, redirect back to the beginning. anywhere else, don't return the back link if request.endpoint == 'main.check_notification': return url_for('main.send_test', service_id=service_id, template_id=template_id, help=get_help_argument()) else: return None elif step_index == 0: if current_user.has_permissions('view_activity'): return url_for( '.view_template', service_id=service_id, template_id=template_id, ) else: return url_for( '.choose_template', service_id=service_id, ) else: return url_for( 'main.send_one_off_step', service_id=service_id, template_id=template_id, step_index=step_index - 1, )
def abandon_release(name): session = current_app.db.session try: release = session.query(Release).filter(Release.name == name).one() # we must require scope which depends on product required_permission = f"{SCOPE_PREFIX}/abandon_release/{release.product}" if not current_user.has_permissions(required_permission): user_permissions = ", ".join(current_user.get_permissions()) abort( 401, f"required permission: {required_permission}, user permissions: {user_permissions}" ) # Cancel all submitted task groups first for phase in filter(lambda x: x.submitted and not x.skipped, release.phases): try: actions = fetch_artifact(phase.task_id, "public/actions.json") parameters = fetch_artifact(phase.task_id, "public/parameters.yml") except ArtifactNotFound: logger.info("Ignoring not completed action task %s", phase.task_id) continue hook = generate_action_hook(task_group_id=phase.task_id, action_name="cancel-all", actions=actions, parameters=parameters, input_={}) hooks = get_service("hooks") client_id = hooks.options["credentials"]["clientId"].decode( "utf-8") hook["context"]["clientId"] = client_id hook_payload_rendered = render_action_hook( payload=hook["hook_payload"], context=hook["context"], delete_params=[ "existing_tasks", "release_history", "release_partner_config" ]) logger.info("Cancel phase %s by hook %s with payload: %s", phase.name, hook["hook_id"], hook_payload_rendered) res = hooks.triggerHook(hook["hook_group_id"], hook["hook_id"], hook_payload_rendered) logger.debug("Done: %s", res) release.status = "aborted" session.commit() release_json = release.json except NoResultFound: abort(404) notify_via_irc( release.product, f"Release {release.product} {release.version} build{release.build_number} was just canceled." ) return release_json
def add_release(body): # we must require scope which depends on product required_permission = f'{SCOPE_PREFIX}/add_release/{body["product"]}' if not current_user.has_permissions(required_permission): user_permissions = ', '.join(current_user.get_permissions()) abort(401, f'required permission: {required_permission}, user permissions: {user_permissions}') session = current_app.db.session product = body['product'] r = Release( product=product, version=body['version'], branch=body['branch'], revision=body['revision'], build_number=body['build_number'], release_eta=body.get('release_eta'), status='scheduled', partial_updates=body.get('partial_updates'), product_key=body.get('product_key'), ) try: r.generate_phases( partner_urls=current_app.config.get('PARTNERS_URL'), github_token=current_app.config.get('GITHUB_TOKEN'), ) session.add(r) session.commit() release = r.json except UnsupportedFlavor as e: raise BadRequest(description=e.description) notify_via_irc(product, f'New release ({product} {r.version} build{r.build_number}) was just created.') return release, 201
def manage_template_folder(service_id, template_folder_id): template_folder = current_service.get_template_folder_with_user_permission_or_403(template_folder_id, current_user) form = TemplateFolderForm( name=template_folder['name'], users_with_permission=template_folder.get('users_with_permission', None), all_service_users=[user for user in current_service.active_users if user.id != current_user.id] ) if form.validate_on_submit(): if current_user.has_permissions("manage_service") and form.users_with_permission.all_service_users: users_with_permission = form.users_with_permission.data + [current_user.id] else: users_with_permission = None template_folder_api_client.update_template_folder( current_service.id, template_folder_id, name=form.name.data, users_with_permission=users_with_permission ) return redirect( url_for('.choose_template', service_id=service_id, template_folder_id=template_folder_id) ) return render_template( 'views/templates/manage-template-folder.html', form=form, template_folder_path=current_service.get_template_folder_path(template_folder_id), current_service_id=current_service.id, template_folder_id=template_folder_id, template_type="all", )
def view_template(service_id, template_id): if not current_user.has_permissions('view_activity'): return redirect( url_for('.send_one_off', service_id=service_id, template_id=template_id)) template = service_api_client.get_service_template( service_id, str(template_id))['data'] if template["template_type"] == "letter": letter_contact_details = service_api_client.get_letter_contacts( service_id) default_letter_contact_block_id = next( (x['id'] for x in letter_contact_details if x['is_default']), None) else: default_letter_contact_block_id = None return render_template( 'views/templates/template.html', template=get_template( template, current_service, expand_emails=True, letter_preview_url=url_for( '.view_letter_template_preview', service_id=service_id, template_id=template_id, filetype='png', ), show_recipient=True, page_count=get_page_count_for_letter(template), ), default_letter_contact_block_id=default_letter_contact_block_id, )
def view_jobs(service_id): page = int(request.args.get('page', 1)) jobs_response = job_api_client.get_page_of_jobs(service_id, page=page) jobs = [add_rate_to_job(job) for job in jobs_response['data']] prev_page = None if jobs_response['links'].get('prev', None): prev_page = generate_previous_dict('main.view_jobs', service_id, page) next_page = None if jobs_response['links'].get('next', None): next_page = generate_next_dict('main.view_jobs', service_id, page) scheduled_jobs = '' if not current_user.has_permissions('view_activity') and page == 1: scheduled_jobs = render_template( 'views/dashboard/_upcoming.html', scheduled_jobs=job_api_client.get_scheduled_jobs(service_id), hide_heading=True, ) return render_template( 'views/jobs/jobs.html', jobs=jobs, page=page, prev_page=prev_page, next_page=next_page, scheduled_jobs=scheduled_jobs, )
def wrap_func(*args, **kwargs): if not current_user.is_authenticated: return current_app.login_manager.unauthorized() if not current_user.has_permissions(*permissions, ** permission_kwargs): abort(403) return func(*args, **kwargs)
def wrap_func(*args, **kwargs): from flask_login import current_user if current_user and current_user.has_permissions(permissions=permissions, admin_override=admin_override, any_=any_): return func(*args, **kwargs) else: abort(403)
def abandon_release(name): session = current_app.db.session try: release = session.query(Release).filter(Release.name == name).one() # we must require scope which depends on product required_permission = f'{SCOPE_PREFIX}/abandon_release/{release.product}' if not current_user.has_permissions(required_permission): user_permissions = ', '.join(current_user.get_permissions()) abort( 401, f'required permission: {required_permission}, user permissions: {user_permissions}' ) # Cancel all submitted task groups first for phase in filter(lambda x: x.submitted, release.phases): try: actions = fetch_actions_json(phase.task_id) except ActionsJsonNotFound: logger.info('Ignoring not completed action task %s', phase.task_id) continue hook = generate_action_hook( task_group_id=phase.task_id, action_name='cancel-all', actions=actions, input_={}, ) hooks = get_service('hooks') client_id = hooks.options['credentials']['clientId'].decode( 'utf-8') hook['context']['clientId'] = client_id hook_payload_rendered = render_action_hook( payload=hook['hook_payload'], context=hook['context'], delete_params=[ 'existing_tasks', 'release_history', 'release_partner_config' ], ) logger.info('Cancel phase %s by hook %s with payload: %s', phase.name, hook['hook_id'], hook_payload_rendered) res = hooks.triggerHook(hook['hook_group_id'], hook['hook_id'], hook_payload_rendered) logger.debug('Done: %s', res) release.status = 'aborted' session.commit() release_json = release.json except NoResultFound: abort(404) notify_via_irc( release.product, f'Release {release.product} {release.version} build{release.build_number} was just canceled.' ) return release_json
def abandon_release(name): session = current_app.db.session release = session.query(Release).filter( Release.name == name).first_or_404() # we must require scope which depends on product required_permission = f"{SCOPE_PREFIX}/abandon_release/{release.product}" if not current_user.has_permissions(required_permission): user_permissions = ", ".join(current_user.get_permissions()) abort( 401, f"required permission: {required_permission}, user permissions: {user_permissions}" ) # Cancel all submitted task groups first for phase in filter(lambda x: x.submitted and not x.skipped, release.phases): try: actions = get_actions(phase.task_id) parameters = get_parameters(phase.task_id) cancel_action = find_action("cancel-all", actions) if not cancel_action: logger.info( "%s %s does not have `cancel-all` action, skipping...", release.name, phase.name) continue except ArtifactNotFound: logger.info("Ignoring not completed action task %s", phase.task_id) continue hook = generate_action_hook(task_group_id=phase.task_id, action_name="cancel-all", actions=actions, parameters=parameters, input_={}) hooks = get_service("hooks") client_id = hooks.options["credentials"]["clientId"].decode("utf-8") hook["context"]["clientId"] = client_id hook_payload_rendered = render_action_hook( payload=hook["hook_payload"], context=hook["context"], delete_params=[ "existing_tasks", "release_history", "release_partner_config" ]) logger.info("Cancel phase %s by hook %s with payload: %s", phase.name, hook["hook_id"], hook_payload_rendered) try: result = hooks.triggerHook(hook["hook_group_id"], hook["hook_id"], hook_payload_rendered) logger.debug("Done: %s", result) except TaskclusterRestFailure as e: abort(400, str(e)) release.status = "aborted" session.commit() logger.info("Canceled release %s", release.name) notify_via_matrix(release.product, f"Release {release.name} was just canceled.") return release.json
def schedule_phase(name, phase): session = current_app.db.session try: phase = session.query(Phase).filter( Release.id == Phase.release_id).filter( Release.name == name).filter(Phase.name == phase).one() except NoResultFound: abort(404) # we must require scope which depends on product required_permission = f"{SCOPE_PREFIX}/schedule_phase/{phase.release.product}/{phase.name}" if not current_user.has_permissions(required_permission): user_permissions = ", ".join(current_user.get_permissions()) abort( 401, f"required permission: {required_permission}, user permissions: {user_permissions}" ) if phase.submitted: abort(409, "Already submitted!") for signoff in phase.signoffs: if not signoff.signed: abort(400, "Pending signoffs") hook = phase.task_json if "hook_payload" not in hook: raise ValueError("Action tasks are not supported") hooks = get_service("hooks") client_id = hooks.options["credentials"]["clientId"].decode("utf-8") extra_context = {"clientId": client_id} result = hooks.triggerHook( hook["hook_group_id"], hook["hook_id"], phase.rendered_hook_payload(extra_context=extra_context)) phase.task_id = result["status"]["taskId"] phase.submitted = True phase.completed_by = current_user.get_id() completed = datetime.datetime.utcnow() phase.completed = completed if all([ph.submitted for ph in phase.release.phases]): phase.release.status = "shipped" phase.release.completed = completed session.commit() root_url = hooks.options["rootUrl"] url = f"{root_url}/tasks/groups/{phase.task_id}" # TODO: Remove the condition after migration if root_url == "https://taskcluster.net": url = "https://tools.taskcluster.net/groups/{phase.task_id}" notify_via_irc( phase.release.product, f"Phase {phase.name} was just scheduled for release {phase.release.product} {phase.release.version} build{phase.release.build_number} - {url}", ) return phase.json
def _require_auth(): required_permission = f"{SCOPE_PREFIX}/github" if not current_user.has_permissions(required_permission): user_permissions = ", ".join(current_user.get_permissions()) abort( 401, f"required permission: {required_permission}, user permissions: {user_permissions}" )
def choose_template(service_id, template_type="all", template_folder_id=None): template_folder = current_service.get_template_folder(template_folder_id) user_has_template_folder_permission = current_user.has_template_folder_permission( template_folder) template_list = TemplateList(current_service, template_type, template_folder_id, current_user) templates_and_folders_form = TemplateAndFoldersSelectionForm( all_template_folders=current_service.get_user_template_folders( current_user), template_list=template_list, template_type=template_type, allow_adding_letter_template=current_service.has_permission("letter"), allow_adding_copy_of_template=(current_service.all_templates or len(current_user.service_ids) > 1), ) option_hints = {template_folder_id: "current folder"} if request.method == "POST" and templates_and_folders_form.validate_on_submit( ): if not current_user.has_permissions("manage_templates"): abort(403) try: return process_folder_management_form(templates_and_folders_form, template_folder_id) except HTTPError as e: flash(e.message) if "templates_and_folders" in templates_and_folders_form.errors: flash(_("Select at least one template or folder")) initial_state = request.args.get("initial_state") if request.method == "GET" and initial_state: templates_and_folders_form.op = initial_state sending_view = request.args.get("view") == "sending" return render_template( "views/templates/choose.html", current_template_folder_id=template_folder_id, template_folder_path=current_service.get_template_folder_path( template_folder_id), template_list=template_list, show_search_box=current_service.count_of_templates_and_folders > 7, show_template_nav=(current_service.has_multiple_template_types and (len(current_service.all_templates) > 2)), sending_view=sending_view, template_nav_items=get_template_nav_items(template_folder_id, sending_view), template_type=template_type, search_form=SearchByNameForm(), templates_and_folders_form=templates_and_folders_form, move_to_children=templates_and_folders_form.move_to.children(), user_has_template_folder_permission=user_has_template_folder_permission, option_hints=option_hints, )
def wrap_func(*args, **kwargs): if current_user and current_user.is_authenticated: if current_user.has_permissions(*permissions, **permission_kwargs): return func(*args, **kwargs) else: abort(403) else: abort(401)
def schedule_phase(name, phase): session = current_app.db.session try: phase = session.query(Phase) \ .filter(Release.id == Phase.release_id) \ .filter(Release.name == name) \ .filter(Phase.name == phase).one() except NoResultFound: abort(404) # we must require scope which depends on product required_permission = f'{SCOPE_PREFIX}/schedule_phase/{phase.release.product}/{phase.name}' if not current_user.has_permissions(required_permission): user_permissions = ', '.join(current_user.get_permissions()) abort( 401, f'required permission: {required_permission}, user permissions: {user_permissions}' ) if phase.submitted: abort(409, 'Already submitted!') for signoff in phase.signoffs: if not signoff.signed: abort(400, 'Pending signoffs') hook = phase.task_json if 'hook_payload' not in hook: raise ValueError('Action tasks are not supported') hooks = get_service('hooks') client_id = hooks.options['credentials']['clientId'].decode('utf-8') extra_context = {'clientId': client_id} result = hooks.triggerHook( hook['hook_group_id'], hook['hook_id'], phase.rendered_hook_payload(extra_context=extra_context), ) phase.task_id = result['status']['taskId'] phase.submitted = True phase.completed_by = current_user.get_id() completed = datetime.datetime.utcnow() phase.completed = completed if all([ph.submitted for ph in phase.release.phases]): phase.release.status = 'shipped' phase.release.completed = completed session.commit() notify_via_irc( phase.release.product, f'Phase {phase.name} was just scheduled ' f'for release {phase.release.product} {phase.release.version} ' f'build{phase.release.build_number} - ' f'(https://tools.taskcluster.net/groups/{phase.task_id})') return phase.json
def phase_signoff(name, phase, body): session = current_app.db.session signoff = session.query(XPISignoff).filter( XPISignoff.uid == body).first_or_404() if signoff.signed: abort(409, "Already signed off") phase_obj = (session.query(XPIPhase).filter( XPIRelease.id == XPIPhase.release_id).filter( XPIRelease.name == name).filter( XPIPhase.name == phase).first_or_404()) # we must require scope which depends on product and phase name xpi_type = _xpi_type(phase_obj.release.revision, phase_obj.release.xpi_name) required_permission = f"{SCOPE_PREFIX}/phase_signoff/xpi/{xpi_type}/{signoff.phase.name}" if not current_user.has_permissions( required_permission) and not XPI_LAX_SIGN_OFF: user_permissions = ", ".join(current_user.get_permissions()) abort( 401, f"required permission: {required_permission}, user permissions: {user_permissions}" ) # Prevent the same user signing off for multiple signoffs users_ldap = current_user.get_ldap_groups() users_email = current_user.get_id() if users_email in [s.completed_by for s in phase_obj.signoffs] and not XPI_LAX_SIGN_OFF: abort(409, f"Already signed off by {users_email}") # signoff.permissions corresponds to the group in settings.py ldap_groups = current_app.config.get("LDAP_GROUPS", {}) ldap_group = ldap_groups.get(signoff.permissions, []) if not set(users_ldap).intersection( set(ldap_group)) and not XPI_LAX_SIGN_OFF: abort(401, f"User `{users_email}` is not in the `{signoff.permissions}`") signoff.completed = datetime.datetime.utcnow() signoff.signed = True signoff.completed_by = users_email session.commit() signoffs = [s.json for s in phase_obj.signoffs] # Schedule the phase when all signoffs are done if all([s.signed for s in phase_obj.signoffs]): schedule_phase(name, phase) release = phase_obj.release logger.info("Phase %s of %s signed off by %s", phase, release.name, users_email) notify_via_matrix( "xpi", f"Phase {phase} of {release.name} signed off by {users_email}") return dict(signoffs=signoffs)
def get_all_challenges(): challenges = ChallengeManager().get_all() if current_user.is_anonymous or not current_user.has_permissions(["admin"]): for challenge in challenges: for flag in challenge.flags: flag["secret"] = "" if challenge.hints is not None: for hint in challenge.hints: hint["text"] = "" return challenges
def wrap_func(*args, **kwargs): if current_user and current_user.is_authenticated: if current_user.has_permissions(permissions=permissions, admin_override=admin_override, any_=any_): return func(*args, **kwargs) else: abort(403) else: abort(401)
def wrapped(*args, **kwargs): if __WITH_USERS__: if not current_user.is_authenticated: emit("auth_required") elif current_user.has_permissions(*perms): return f(*args, **kwargs) else: raise Exception( f"You don't have the required permissions. \n These are your permissions: {current_user.permissions}" ) else: return f(*args, **kwargs)
def wrap_func(*args, **kwargs): if current_user and current_user.is_authenticated: if current_user.has_permissions( permissions=permissions, admin_override=admin_override, any_=any_ ): return func(*args, **kwargs) else: abort(403) else: abort(401)
def add_release(body): # we must require scope which depends on product required_permission = f'{SCOPE_PREFIX}/add_release/{body["product"]}' if not current_user.has_permissions(required_permission): user_permissions = ", ".join(current_user.get_permissions()) abort( 401, f"required permission: {required_permission}, user permissions: {user_permissions}" ) product = body["product"] branch = body["branch"] product_disabled = branch in get_disabled_products().get(product, []) if current_user.type == AuthType.TASKCLUSTER and product_disabled: abort(401, "Taskcluster based submissions are disabled") session = current_app.db.session partial_updates = body.get("partial_updates") if partial_updates == "auto": if product not in [ Product.FIREFOX.value, Product.DEVEDITION.value ] or branch not in ["try", "releases/mozilla-beta", "projects/maple"]: abort(400, "Partial suggestion works for automated betas only") partial_updates = _suggest_partials(product=product, branch=branch) release = Release( branch=branch, build_number=body["build_number"], partial_updates=partial_updates, product_key=body.get("product_key"), product=product, release_eta=body.get("release_eta"), repo_url=body.get("repo_url", ""), revision=body["revision"], status="scheduled", version=body["version"], ) try: release.generate_phases() session.add(release) session.commit() except UnsupportedFlavor as e: raise BadRequest(description=e.description) except TaskclusterRestFailure as e: # Report back Taskcluster failure for better visibility of the actual # issue. Usually it happens when we cannot find the indexed task. abort(400, str(e)) logger.info("New release of %s", release.name) notify_via_irc(product, f"New release of {release.name}") return release.json, 201
def decorated(*args, **kwargs): # TODO: WORKAROUND: # when it is an API key, always allow it if current_user.is_api_user: has_permissions = True else: has_permissions = current_user.has_permissions(self.permissions) if has_permissions: return fn(*args, **kwargs) else: abort(403)
def get_skip_link(step_index, template): if ( request.endpoint == 'main.send_one_off_step' and step_index == 0 and template.template_type in ("sms", "email") and not (template.template_type == 'sms' and current_user.mobile_number is None) and current_user.has_permissions('manage_templates', 'manage_service') ): return ( 'Use my {}'.format(first_column_headings[template.template_type][0]), url_for('.send_one_off_to_myself', service_id=current_service.id, template_id=template.id), )
def add_release(body): # we must require scope which depends on product required_permission = f'{SCOPE_PREFIX}/add_release/{body["product"]}' if not current_user.has_permissions(required_permission): user_permissions = ", ".join(current_user.get_permissions()) abort( 401, f"required permission: {required_permission}, user permissions: {user_permissions}" ) product = body["product"] branch = body["branch"] product_disabled = branch in get_disabled_products().get(product, []) if current_user.type == AuthType.TASKCLUSTER and product_disabled: abort(401, "Taskcluster based submissions are disabled") session = current_app.db.session partial_updates = body.get("partial_updates") if partial_updates == "auto": if product not in [ Product.FIREFOX.value, Product.DEVEDITION.value ] or branch not in ["try", "releases/mozilla-beta", "projects/maple"]: abort(400, "Partial suggestion works for automated betas only") partial_updates = _suggest_partials(product=product, branch=branch) r = Release( product=product, version=body["version"], branch=branch, revision=body["revision"], build_number=body["build_number"], release_eta=body.get("release_eta"), status="scheduled", partial_updates=partial_updates, product_key=body.get("product_key"), ) try: r.generate_phases(partner_urls=current_app.config.get("PARTNERS_URL"), github_token=current_app.config.get("GITHUB_TOKEN")) session.add(r) session.commit() release = r.json except UnsupportedFlavor as e: raise BadRequest(description=e.description) notify_via_irc( product, f"New release ({product} {r.version} build{r.build_number}) was just created." ) return release, 201
def service_dashboard(service_id): if session.get('invited_user'): session.pop('invited_user', None) session['service_id'] = service_id if not current_user.has_permissions('view_activity'): return redirect(url_for('main.choose_template', service_id=service_id)) return render_template('views/dashboard/dashboard.html', updates_url=url_for(".service_dashboard_updates", service_id=service_id), partials=get_dashboard_partials(service_id))
def serialize_contributor(contributor, link=None): ''' Helper to serialize a contributor & its role ''' assert isinstance(contributor, Contributor) out = { 'id': contributor.id, 'email': contributor.email, 'name': contributor.name, 'avatar': contributor.avatar_url, 'karma': contributor.karma or 0, 'comment_public': contributor.comment_public or '', } if current_user.has_permissions(SCOPES_ADMIN): # Only admins can see/edit the private comment out['comment_private'] = contributor.comment_private or '' if link is not None: assert isinstance(link, BugContributor) out['roles'] = link.roles.split(',') return out
def wrapper(fn, instance, args, kwargs): if not (current_user and current_user.is_authenticated): return flask.abort(401) elif not current_user.has_permissions(*tokens): return flask.abort(403) return fn(*args, **kwargs)
def current_user_has_permissions(*tokens): """Returns True IFF the current session belongs to an authenticated user who has all of the given permission tokens.""" return (current_user and current_user.is_authenticated and current_user.has_permissions(*tokens))
def __call__(self): return self.permissions <= current_user.has_permissions()