def post(self, request, *args, **kwargs): job = get_object_or_404( Job, id=kwargs[self.job_id_url_kwarg], type_id=_DeletorType.id, ) if job.user != request.user: raise PermissionDenied('You can only terminate your deletion jobs.') if not job.is_finished: raise ConflictError('A non finished job cannot be terminated.') jresult = JobResult.objects.filter(job=job).first() if jresult is not None: messages = jresult.messages raise ConflictError( gettext('Error. Please contact your administrator.') if messages is None else '\n'.join(messages) ) job.delete() return HttpResponse()
def check_rfield(self, rfield, report): if rfield.report_id != report.id: # NB: compare IDs to avoid a query raise ConflictError('This Field & this Report do not match.') if not rfield.sub_report_id: raise ConflictError( 'This Field has no Report, so can no be (un)selected')
def set_selected(request): POST = request.POST field_id = get_from_POST_or_404(POST, 'field_id', cast=int) report_id = get_from_POST_or_404(POST, 'report_id', cast=int) try: checked = bool(int(POST.get('checked', 0))) except ValueError: checked = False with atomic(): report = get_object_or_404(Report.objects.select_for_update(), id=report_id) request.user.has_perm_to_change_or_die(report) rfield = get_object_or_404(Field, id=field_id) if rfield.report_id != report.id: raise ConflictError('This Field & this Report do not match.') if not rfield.sub_report_id: raise ConflictError( 'This Field has no Report, so can no be (un)selected') report = rfield.report if rfield.selected != checked: if checked: # Only one Field should be selected report.fields.exclude(pk=rfield.pk).update(selected=False) rfield.selected = checked rfield.save() return HttpResponse()
def check_instance_permissions(self, instance, user): if not instance.is_custom: raise ConflictError( gettext('You cannot delete this calendar: it is not custom.')) if instance.user_id != user.id: raise PermissionDenied( gettext('You are not allowed to delete this calendar.')) if not Calendar.objects.filter(user=user).exclude( id=instance.id).exists(): raise ConflictError( gettext('You cannot delete your last calendar.')) ctype = ContentType.objects.get_for_model(Calendar) dcom = DeletionCommand.objects.filter(content_type=ctype).first() if dcom is not None: if dcom.job.status == Job.STATUS_OK: dcom.job.delete() else: # TODO: if STATUS_ERROR, show a popup with the errors ? raise ConflictError( gettext( 'A deletion process for an instance of «{model}» already exists.' ).format(model=ctype))
def get_form_class(self): creator = self.get_model_conf().creator if not creator.enable_func(user=self.request.user): raise ConflictError('This model has been disabled for creation.') if creator.url_name is not None: raise ConflictError('This model does not use this creation view.') return creator.form_class
def get_form_class(self): deletor = self.get_model_conf().deletor if not deletor.enable_func(instance=self.object, user=self.request.user): raise ConflictError('This model has been disabled for deletion.') if deletor.url_name is not None: raise ConflictError('This model does not use this deletion view.') return deletor.form_class
def get_linkable_ctypes(self): rfield = self.object hand = rfield.hand if hand is None: raise ConflictError( 'This field is invalid') # TODO: force brick to reload ctypes = rfield.hand.get_linkable_ctypes() if ctypes is None: raise ConflictError('This field is not linkable') return ctypes
def check_instance_permissions(self, instance, user): if instance.custom_field.is_deleted: raise ConflictError(gettext('This custom field is deleted.')) dcom = DeletionCommand.objects.filter( content_type=ContentType.objects.get_for_model( type(instance)), ).first() if dcom is not None: if dcom.job.status == Job.STATUS_OK: dcom.job.delete() else: # TODO: if STATUS_ERROR, show a popup with the errors ? raise ConflictError( gettext('A deletion process for a choice already exists.'))
def post(self, request, **kwargs): user_id = self.kwargs[self.user_id_url_kwarg] user = request.user if int(user_id) == user.id: raise ConflictError( gettext("You can't deactivate the current user.")) with atomic(): user_to_deactivate = get_object_or_404( get_user_model().objects.select_for_update(), id=user_id, ) if user_to_deactivate.is_staff and not user.is_staff: return HttpResponse( gettext("You can't deactivate a staff user."), status=400, ) if user_to_deactivate.is_active: user_to_deactivate.is_active = False user_to_deactivate.save() return HttpResponse()
def get_group_id(self): group_id = int(self.kwargs[self.group_id_url_kwarg]) if group_id >= len(self.get_groups()): raise ConflictError(f'The group ID "{group_id}" is invalid.') return group_id
def post(self, request, *args, **kwargs): target = get_from_POST_or_404(request.POST, self.target_order_arg, cast=int) self.object = cfci = self.get_cfci_for_update() desc = self.get_customform_descriptor() group_id = self.get_group_id() groups = [*self.get_groups()] if target > len(groups): raise ConflictError(f'The target "{target}" is too big.') moved_group = groups.pop(group_id) groups.insert(target, moved_group) cfci.store_groups( FieldGroupList( model=desc.model, groups=groups, cell_registry=desc.build_cell_registry(), )) cfci.save() # TODO: only if changed ? return HttpResponse()
def post(self, request, *args, **kwargs): layout = get_from_POST_or_404(request.POST, self.layout_arg) if layout not in LAYOUTS: raise ConflictError(f'The layout "{layout}" is invalid.') self.object = cfci = self.get_cfci_for_update() desc = self.get_customform_descriptor() group_id = self.get_group_id() # groups = [ # FieldGroup(name=group.name, cells=group.cells, layout=layout) # if i == group_id else # group # for i, group in enumerate(self.get_groups()) # ] groups = [*self.get_groups()] groups[group_id]._layout = layout cfci.store_groups( FieldGroupList( model=desc.model, groups=groups, cell_registry=desc.build_cell_registry(), )) cfci.save() # TODO: only if changed ? return HttpResponse()
def get_group(self): group = self.get_groups()[self.get_group_id()] if isinstance(group, ExtraFieldGroup): raise ConflictError('An extra group cannot be edited.') return group
def get_relation_types(self): subject = self.get_related_entity() subject_ctype = subject.entity_type rtypes = [] subjects_prop_ids = None # TODO: lazy object for rtype in RelationType.objects.filter(id__in=bricks.MailsHistoryBrick .relation_type_deps): if not rtype.is_compatible(subject_ctype): continue # TODO: unit test # TODO: factorise with RelationsAdding needed_property_types = [*rtype.subject_properties.all()] if needed_property_types: if subjects_prop_ids is None: subjects_prop_ids = {*subject.properties.values_list('type', flat=True)} if any(needed_ptype.id not in subjects_prop_ids for needed_ptype in needed_property_types ): continue rtypes.append(rtype.id) # TODO: unit test if not rtypes: raise ConflictError(gettext('No type of relationship is compatible.')) return rtypes
def check_related_entity_permissions(self, entity, user): user.has_perm_to_view_or_die(entity) # TODO: move to EntityRelatedMixin ?? if entity.is_deleted: raise ConflictError( 'This entity cannot be converted because it is deleted.')
def get_form_class(self): form_class = self.forms_registry.get_form(self.get_created_model()) if form_class is None: raise ConflictError('This type of resource has no quick form.') return form_class
def get_target_order(self): """Returns the future order (starting at 1) of the instance we want to move.""" order = get_from_POST_or_404(self.request.POST, self.target_order_post_argument, int) if order < 1: raise ConflictError('Target order must be greater than or equal to 1.') return order
def check_related_ctype(self, ctype): self.request.user.has_perm_to_access_or_die(ctype.app_label) model = ctype.model_class() if not issubclass(model, CremeEntity): raise ConflictError( 'This model is not a entity model: {}'.format(model))
def search_person(request): search = get_from_GET_or_404(request.GET, 'search') if len(search) < 3: raise ConflictError( _('Your search is too short.')) # TODO: client-side validation # TODO: populate employers contacts = EntityCredentials.filter( request.user, Contact.objects.exclude(is_deleted=True).filter( Q(first_name__icontains=search) | Q(last_name__icontains=search) | Q( relations__type__in=( persons_constants.REL_SUB_EMPLOYED_BY, persons_constants.REL_SUB_MANAGES, ), relations__object_entity__header_filter_search_field__icontains =search, )).distinct())[:30] orgas = EntityCredentials.filter( request.user, Organisation.objects.exclude(is_deleted=True).filter( name__icontains=search))[:30] return render( request, 'mobile/search.html', { 'search': search, 'contacts': contacts, 'contact_model': Contact, 'organisations': orgas, 'orga_model': Organisation, })
def _get_task(self): try: return Relation.objects.get(subject_entity=self.instance.pk, type=REL_SUB_LINKED_2_PTASK) \ .object_entity \ .get_real_entity() except Relation.DoesNotExist as e: raise ConflictError('This Activity is not related to a project task.') from e
def export(self, entity, user): template = get_template(self.template_path) with override(language=self.flavour.language): html = template.render(self.get_context_data(object=entity)) # response = HttpResponse(content_type='application/pdf') # response['Content-Disposition'] = \ # f'attachment; filename="{entity._meta.verbose_name}.pdf"' response = HttpResponse( headers={ 'Content-Type': 'application/pdf', 'Content-Disposition': f'attachment; filename="{entity._meta.verbose_name}.pdf"', }) pisa_status = pisa.CreatePDF( html, dest=response, # TODO ? see https://xhtml2pdf.readthedocs.io/en/latest/usage.html#using-xhtml2pdf-in-django # NOQA # link_callback=link_callback, ) if pisa_status.err: # TODO: test ; use pisa_status.log ? raise ConflictError( _('An error happened while generating the PDF file.')) return response
def get_queryset(self): qs = self.model._default_manager.all() cursed_items = self.filter_non_exportable_items(qs) if cursed_items: ctypes = {bdl.content_type for bdl in cursed_items} try: ctypes.remove(None) except KeyError: default_config = False else: default_config = True ct_labels = sorted((str(ct) for ct in ctypes), key=collator.sort_key) if default_config: ct_labels.insert(0, _('Default configuration')) raise ConflictError( _( 'The configuration of blocks for detailed-views cannot be ' 'exported because it contains references to some ' 'instance-blocks ({blocks}), which are not managed, for the ' 'following cases: {models}.' ).format( blocks=self.items_to_str(cursed_items), models=', '.join(ct_labels) ) ) return qs
def get_graph_data(self, request, order): brick_item = self.get_instance_brick_item() entity = self.get_related_entity() brick = brick_registry.get_brick_4_instance(brick_item, entity=entity) try: fetcher = brick.fetcher except AttributeError as e: raise ConflictError('Invalid brick: {e}') from e # TODO: test try: x, y = fetcher.fetch_4_entity( entity=entity, order=order, user=request.user, ) except (GraphFetcher.IncompatibleContentType, GraphFetcher.UselessResult): logger.exception( 'Fetching error in %s.get_graph_data()', type(self).__name__, ) x = y = None return fetcher.graph, x, y
def delete_user_calendar(request): calendar = get_object_or_404(Calendar, pk=get_from_POST_or_404(request.POST, 'id')) user = request.user # TODO: factorise calendar credentials functions ? if not calendar.is_custom or (not user.is_superuser and calendar.user_id != user.id): raise PermissionDenied( ugettext('You are not allowed to delete this calendar.')) # Attach all existing activities to the default calendar replacement_calendar = Calendar.get_user_default_calendar(user) if replacement_calendar == calendar: replacement_calendar = Calendar.objects.filter(user=user)\ .exclude(id=calendar.id)\ .order_by('id')\ .first() if replacement_calendar is None: raise ConflictError( ugettext('You cannot delete your last calendar.')) for activity in calendar.activity_set.all(): activity.calendars.add(replacement_calendar) calendar.delete()
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # TODO: should be in the view ? field_name = self.field_name if FieldsConfig.get_4_model(self._entity.__class__).is_fieldname_hidden(field_name): raise ConflictError('"{}" is hidden & so it cannot be edited'.format(field_name))
def check_related_entity_permissions(self, entity, user): super().check_related_entity_permissions(entity=entity, user=user) if not entity.is_alive(): raise ConflictError(gettext("You can't add a resource or a working " "period to a task which has status «{}»" ).format(entity.tstatus.name) )
def get_customform_descriptor(self): desc = super().get_customform_descriptor() if not next(desc.extra_group_classes, None): raise ConflictError( 'This custom-form does not propose extra group.') return desc
def perform_deletion(self, request): try: get_object_or_404( self.model, pk=get_from_POST_or_404(request.POST, self.id_arg), ).delete() except ProtectedError as e: raise ConflictError(e.args[0])
def __init__(self, *args, **kwargs): # super(FieldConfigWizard._ModelStep, self).__init__(*args, **kwargs) super().__init__(*args, **kwargs) if not self.ctypes: raise ConflictError( ugettext( 'All configurable types of resource are already configured.' ))
def get_email_ids(self, request): try: return [ int(s) for s in get_from_POST_or_404( request.POST, self.email_ids_arg).split(',') if s.strip() ] except ValueError as e: raise ConflictError(str(e)) from e