def _process(self, url): if editing_settings.get(self.event, 'service_url'): raise BadRequest('Service URL already set') url = url.rstrip('/') info = check_service_url(url) if info['error'] is not None: abort(422, messages={'url': [info['error']]}) if not editing_settings.get(self.event, 'service_event_identifier'): editing_settings.set(self.event, 'service_event_identifier', make_event_identifier(self.event)) editing_settings.set_multi(self.event, { 'service_url': url, 'service_token': unicode(uuid4()), }) # we need to commit the token so the service can already use it when processing # the enabled event in case it wants to set up tags etc db.session.commit() try: service_handle_enabled(self.event) except ServiceRequestFailed as exc: editing_settings.delete(self.event, 'service_url', 'service_token') db.session.commit() raise ServiceUnavailable( _('Could not register event with service: {}').format(exc)) except Exception: editing_settings.delete(self.event, 'service_url', 'service_token') db.session.commit() raise return '', 204
def _process_args(self): RHEditingManagementBase._process_args(self) uuid = request.view_args['uuid'] conditions = editing_settings.get(self.event, 'review_conditions') self.uuid = unicode(uuid) if self.uuid not in conditions: raise NotFound
def _clone_review_conditions(self, new_event): review_conditions = editing_settings.get(self.old_event, 'review_conditions') new_conditions = OrderedDict( self._build_review_conditions(new_event, cond) for cond in review_conditions.viewvalues()) editing_settings.set(new_event, 'review_conditions', new_conditions)
def _process(self): if self.editable: raise UserValueError(_('Editable already exists')) args = parser.parse({ 'files': EditingFilesField(self.event, self.contrib, self.editable_type, required=True) }) service_url = editing_settings.get(self.event, 'service_url') initial_state = InitialRevisionState.new if service_url else InitialRevisionState.ready_for_review editable = create_new_editable(self.contrib, self.editable_type, session.user, args['files'], initial_state) if service_url: try: service_handle_new_editable(editable, session.user) except ServiceRequestFailed: raise ServiceUnavailable( _('Submission failed, please try again later.')) return '', 201
def _process(self, action, comment): argmap = {'tags': EditingTagsField(self.event, missing=set())} if action in (EditingReviewAction.update, EditingReviewAction.update_accept): argmap['files'] = EditingFilesField(self.event, self.contrib, self.editable_type, allow_claimed_files=True, required=True) args = parser.parse(argmap, unknown=EXCLUDE) service_url = editing_settings.get(self.event, 'service_url') new_revision = review_editable_revision(self.revision, session.user, action, comment, args['tags'], args.get('files')) publish = True if service_url: try: resp = service_handle_review_editable(self.editable, session.user, action, self.revision, new_revision) publish = resp.get('publish', True) except ServiceRequestFailed: raise ServiceUnavailable( _('Failed processing review, please try again later.')) if publish and action in (EditingReviewAction.accept, EditingReviewAction.update_accept): publish_editable_revision(new_revision or self.revision) return '', 204
def _process(self): if not editing_settings.get(self.event, 'service_url'): return jsonify(connected=False, error=None, status=None) status = service_get_status(self.event) return jsonify(connected=True, error=status['error'], status=status['status'])
def review_conditions_valid(self): review_conditions = editing_settings.get(self.event, 'review_conditions').values() file_types = {file.file_type_id for file in self.revisions[-1].files} if not review_conditions: return True return any(file_types >= set(cond) for cond in review_conditions)
def _check_revision_access(self): if not editing_settings.get(self.event, 'service_url'): return False # It's up to the editing service to decide who can do what, so we # just require the user to have more than just read access return (self.editable.can_perform_submitter_actions(session.user) or self.editable.can_perform_editor_actions(session.user))
def _process_args(self): RHEditingManagementBase._process_args(self) self.editable_type = EditableType[request.view_args['type']] uuid = request.view_args['uuid'] conditions = editing_settings.get(self.event, self.editable_type.name + '_review_conditions') self.uuid = unicode(uuid) if self.uuid not in conditions: raise NotFound
def _clone_review_conditions(self, new_event): for type_ in EditableType: review_conditions = editing_settings.get( self.old_event, type_.name + '_review_conditions') new_conditions = OrderedDict( self._build_review_conditions(new_event, cond) for cond in review_conditions.viewvalues()) editing_settings.set(new_event, type_.name + '_review_conditions', new_conditions)
def _get_headers(event, include_token=True): headers = { 'Accept': 'application/json', 'User-Agent': f'Indico/{indico.__version__}' } if include_token: headers['Authorization'] = 'Bearer {}'.format( editing_settings.get(event, 'service_token')) return headers
def _get_custom_actions(self): if not editing_settings.get(self.event, 'service_url'): return [] try: return service_get_custom_actions(self.editable, self.editable.revisions[-1], session.user) except ServiceRequestFailed: # unlikely to fail, but if it does we don't break the whole timeline return []
def enabled_editables(self): """Return all submitted editables with enabled types.""" from indico.modules.events.editing.settings import editing_settings if not self.event.has_feature('editing'): return [] enabled_editable_types = editing_settings.get(self.event, 'editable_types') enabled_editables = [editable for editable in self.editables if editable.type.name in enabled_editable_types] order = list(EditableType) return sorted(enabled_editables, key=lambda editable: order.index(editable.type))
def _validate_file_types(self, file_types): event = self.context['event'] event_file_types = {ft.id for ft in event.editing_file_types} condition_types = set(file_types) if condition_types - event_file_types: raise ValidationError(_('Invalid file type used')) event_conditions = editing_settings.get(event, 'review_conditions') if any(condition_types == set(event_condition) for event_condition in event_conditions.values()): raise ValidationError(_('Conditions have to be unique'))
def _token_can_access(self): # we need to "fish" the event here because at this point _check_params # hasn't run yet event = Event.get_or_404(int(request.view_args['confId']), is_deleted=False) if not self.SERVICE_ALLOWED or not request.bearer_token: return False event_token = editing_settings.get(event, 'service_token') if request.bearer_token != event_token: raise Unauthorized('Invalid bearer token') return True
def service_handle_enabled(event): data = { 'title': event.title, 'url': event.external_url, 'token': editing_settings.get(event, 'service_token'), 'endpoints': _get_event_endpoints(event) } try: resp = requests.put(_build_url(event, '/event/{}'.format(_get_event_identifier(event))), headers=_get_headers(event, include_token=False), json=data) resp.raise_for_status() except requests.RequestException as exc: _log_service_error(exc, 'Registering event with service failed') raise ServiceRequestFailed(exc)
def _process(self, action, comment): confirm_editable_changes(self.revision, session.user, action, comment) service_url = editing_settings.get(self.event, 'service_url') publish = True if service_url: try: resp = service_handle_review_editable(self.editable, session.user, action, self.revision) publish = resp.get('publish', True) except ServiceRequestFailed: raise ServiceUnavailable(_('Failed processing review, please try again later.')) if publish and action == EditingConfirmationAction.accept: publish_editable_revision(self.revision) return '', 204
def _process_DELETE(self): if EditingRevisionFile.query.with_parent(self.file_type).has_rows(): raise UserValueError(_('Cannot delete file type which already has files')) review_conditions = editing_settings.get(self.event, self.editable_type.name + '_review_conditions') if any(self.file_type.id in cond for cond in review_conditions.values()): raise UserValueError(_('Cannot delete file type which is used in a review condition')) if self.file_type.publishable: is_last = not (EditingFileType.query .with_parent(self.event) .filter(EditingFileType.publishable, EditingFileType.id != self.file_type.id) .has_rows()) if is_last: raise UserValueError(_('Cannot delete the only publishable file type')) delete_file_type(self.file_type) return '', 204
def _process(self): args = parser.parse({ 'files': EditingFilesField(self.event, self.contrib, self.editable_type, allow_claimed_files=True, required=True) }) service_url = editing_settings.get(self.event, 'service_url') new_revision = create_submitter_revision(self.revision, session.user, args['files']) if service_url: try: service_handle_review_editable(self.editable, session.user, EditingReviewAction.update, self.revision, new_revision) except ServiceRequestFailed: raise ServiceUnavailable(_('Failed processing review, please try again later.')) return '', 204
class PaperSchema(mm.Schema): is_in_final_state = Boolean() contribution = Nested(ContributionSchema) event = Nested(PaperEventSchema) revisions = List(Nested(PaperRevisionSchema)) last_revision = Nested(PaperRevisionSchema) state = Nested(PaperRevisionStateSchema) can_judge = Function(lambda paper, ctx: paper.can_judge(ctx.get('user'))) can_comment = Function(lambda paper, ctx: paper.can_comment( ctx.get('user'), check_state=True)) can_review = Function(lambda paper, ctx: paper.can_review(ctx.get('user'))) can_submit_proceedings = Function(lambda paper, ctx: paper.contribution. can_submit_proceedings(ctx.get('user'))) editing_open = Function(lambda paper, ctx: editable_type_settings[ EditableType.paper].get(paper.event, 'submission_enabled')) editing_enabled = Function( lambda paper, ctx: paper.event.has_feature('editing') and 'paper' in editing_settings.get(paper.event, 'editable_types'))
def _process(self, force): if not editing_settings.get(self.event, 'service_url'): raise BadRequest('Service URL not set') status = service_get_status(self.event) notify_service = True if status['error']: if not force: # this only happens if the service went down between loading # the page and sending the disconnect request raise BadRequest('Cannot disconnect service') notify_service = False elif not status['status']['can_disconnect']: raise BadRequest('Cannot disconnect service') if notify_service: try: service_handle_disconnected(self.event) except ServiceRequestFailed as exc: raise ServiceUnavailable(_('Could not disconnect event from service: {}').format(exc)) editing_settings.delete(self.event, 'service_url', 'service_token') return '', 204
def service_handle_enabled(event): data = { 'title': event.title, 'url': event.external_url, 'token': editing_settings.get(event, 'service_token'), 'endpoints': { 'tags': { 'create': url_for('.api_create_tag', event, _external=True), 'list': url_for('.api_tags', event, _external=True) }, 'editable_types': url_for('.api_enabled_editable_types', event, _external=True), 'file_types': { t.name: { 'create': url_for('.api_add_file_type', event, type=t.name, _external=True), 'list': url_for('.api_file_types', event, type=t.name, _external=True), } for t in EditableType } } } try: resp = requests.put(_build_url( event, '/event/{}'.format(_get_event_identifier(event))), headers=_get_headers(event, include_token=False), json=data) resp.raise_for_status() except requests.RequestException as exc: logger.exception('Registering event with service failed') raise ServiceRequestFailed(exc)
def _process_GET(self): return jsonify(editing_settings.get(self.event, 'editable_types'))
def editable_types(self): from indico.modules.events.editing.settings import editing_settings return editing_settings.get(self, 'editable_types')
def _process_DELETE(self): new_conditions = editing_settings.get(self.event, 'review_conditions') del new_conditions[self.uuid] editing_settings.set(self.event, 'review_conditions', new_conditions) return '', 204
def _is_used_in_condition(self, file_type): conditions = editing_settings.get( file_type.event, file_type.type.name + '_review_conditions') return any(file_type.id in cond for cond in conditions.values())
def _get_event_identifier(event): identifier = editing_settings.get(event, 'service_event_identifier') assert identifier return identifier
def _build_url(event, path): return editing_settings.get(event, 'service_url') + path
def _check_revision_access(self): if not editing_settings.get(self.event, 'service_url'): return False # It's up to the editing service to decide who can do what, so we # just require the user to have editable access return self.editable.can_see_timeline(session.user)
def _process_PATCH(self, file_types): new_conditions = editing_settings.get(self.event, 'review_conditions') new_conditions[self.uuid] = file_types editing_settings.set(self.event, 'review_conditions', new_conditions) return '', 204