Ejemplo n.º 1
0
class Scanner(models.Model):
    """A scanner, i.e. a template for actual scanning jobs."""
    objects = InheritanceManager()

    name = models.CharField(max_length=256,
                            unique=True,
                            null=False,
                            verbose_name='Navn')

    organization = models.ForeignKey(Organization,
                                     null=False,
                                     verbose_name='Organisation')

    group = models.ForeignKey(Group,
                              null=True,
                              blank=True,
                              verbose_name='Gruppe')

    schedule = RecurrenceField(max_length=1024,
                               verbose_name='Planlagt afvikling')

    do_cpr_scan = models.BooleanField(default=True, verbose_name='CPR')

    do_name_scan = models.BooleanField(default=False, verbose_name='Navn')

    do_address_scan = models.BooleanField(default=False,
                                          verbose_name='Adresse')

    do_ocr = models.BooleanField(default=False, verbose_name='Scan billeder')

    do_last_modified_check = models.BooleanField(
        default=True, verbose_name='Tjek sidst ændret dato')

    do_cpr_modulus11 = models.BooleanField(default=True,
                                           verbose_name='Tjek modulus-11')

    do_cpr_ignore_irrelevant = models.BooleanField(
        default=True, verbose_name='Ignorer ugyldige fødselsdatoer')

    columns = models.CommaSeparatedIntegerField(max_length=128,
                                                null=True,
                                                blank=True)

    regex_rules = models.ManyToManyField(RegexRule,
                                         blank=True,
                                         verbose_name='Regex regler')

    recipients = models.ManyToManyField(UserProfile,
                                        blank=True,
                                        verbose_name='Modtagere')

    # Spreadsheet annotation and replacement parameters

    # Save a copy of any spreadsheets scanned with annotations
    # in each row where matches were found. If this is enabled and any of
    # the replacement parameters are enabled (e.g. do_cpr_replace), matches
    # will also be replaced with the specified text (e.g. cpr_replace_text).
    output_spreadsheet_file = models.BooleanField(default=False)

    # Replace CPRs?
    do_cpr_replace = models.BooleanField(default=False)

    # Text to replace CPRs with
    cpr_replace_text = models.CharField(max_length=2048, null=True, blank=True)

    # Replace names?
    do_name_replace = models.BooleanField(default=False)

    # Text to replace names with
    name_replace_text = models.CharField(max_length=2048,
                                         null=True,
                                         blank=True)
    # Replace addresses?
    do_address_replace = models.BooleanField(default=False)

    # Text to replace addresses with
    address_replace_text = models.CharField(max_length=2048,
                                            null=True,
                                            blank=True)

    is_running = models.BooleanField(default=False)

    @property
    def schedule_description(self):
        """A lambda for creating schedule description strings."""
        rules = [r for r in self.schedule.rrules]  # Use r.to_text() to render
        dates = [d for d in self.schedule.rdates]
        if len(rules) > 0 or len(dates) > 0:
            return u"Ja"
        else:
            return u"Nej"

    # Run error messages
    ALREADY_RUNNING = ("Scanneren kunne ikke startes," +
                       " fordi der allerede er en scanning i gang for den.")
    NO_VALID_DOMAINS = ("Scanneren kunne ikke startes," +
                        " fordi den ikke har nogen gyldige domæner.")

    # DON'T USE DIRECTLY !!!
    # Use process_urls property instead.
    encoded_process_urls = models.CharField(max_length=262144,
                                            null=True,
                                            blank=True)
    # Booleans for control of scanners run from web service.
    do_run_synchronously = models.BooleanField(default=False)
    is_visible = models.BooleanField(default=True)

    def _get_process_urls(self):
        s = self.encoded_process_urls
        if s:
            urls = json.loads(s)
        else:
            urls = []
        return urls

    def _set_process_urls(self, urls):
        self.encoded_process_urls = json.dumps(urls)

    process_urls = property(_get_process_urls, _set_process_urls)

    # First possible start time
    FIRST_START_TIME = datetime.time(18, 0)
    # Amount of quarter-hours that can be added to the start time
    STARTTIME_QUARTERS = 6 * 4

    def get_start_time(self):
        """The time of day the Scanner should be automatically started."""
        added_minutes = 15 * (self.pk % Scanner.STARTTIME_QUARTERS)
        added_hours = int(added_minutes / 60)
        added_minutes -= added_hours * 60
        return Scanner.FIRST_START_TIME.replace(
            hour=Scanner.FIRST_START_TIME.hour + added_hours,
            minute=Scanner.FIRST_START_TIME.minute + added_minutes)

    @property
    def has_valid_domains(self):
        return len([d for d in self.domains.all() if d.validation_status]) > 0

    @classmethod
    def modulo_for_starttime(cls, time):
        """Convert a datetime.time object to the corresponding modulo value.

        The modulo value can be used to search the database for scanners that
        should be started at the given time by filtering a query with:
            (WebScanner.pk % WebScanner.STARTTIME_QUARTERS) == <modulo_value>
        """
        if (time < cls.FIRST_START_TIME):
            return None
        hours = time.hour - cls.FIRST_START_TIME.hour
        minutes = 60 * hours + time.minute - cls.FIRST_START_TIME.minute
        return int(minutes / 15)

    @property
    def display_name(self):
        """The name used when displaying the scanner on the web page."""
        return "WebScanner '%s'" % self.name

    def __unicode__(self):
        """Return the name of the scanner."""
        return self.name

    def __str__(self):
        """Return the name of the scanner."""
        return self.__unicode__()

    def run(self, test_only=False, blocking=False, user=None):
        """Run a scan with the Scanner.

        Return the Scan object if we started the scanner.
        Return None if there is already a scanner running,
        or if there was a problem running the scanner.
        If test_only is True, only check if we can run a scan, don't actually
        run one.
        """
        if self.is_running:
            return Scanner.ALREADY_RUNNING

        if not self.has_valid_domains:
            return Scanner.NO_VALID_DOMAINS

        # Create a new Scan
        scan = self.create_scan()
        if isinstance(scan, str):
            return scan
        # Add user as recipient on scan
        if user:
            scan.recipients.add(user.profile)
        # Get path to run script
        SCRAPY_WEBSCANNER_DIR = os.path.join(settings.PROJECT_DIR,
                                             "scrapy-webscanner")

        if test_only:
            return scan

        if not os.path.exists(scan.scan_log_dir):
            os.makedirs(scan.scan_log_dir)
        log_file = open(scan.scan_log_file, "a")

        if not os.path.exists(scan.scan_output_files_dir):
            os.makedirs(scan.scan_output_files_dir)

        try:
            process = Popen(
                [os.path.join(SCRAPY_WEBSCANNER_DIR, "run.sh"),
                 str(scan.pk)],
                cwd=SCRAPY_WEBSCANNER_DIR,
                stderr=log_file,
                stdout=log_file)
            if blocking:
                process.communicate()
        except Exception as e:
            print(e)
            return None
        return scan

    class Meta:
        abstract = False
        ordering = ['name']
        db_table = 'os2webscanner_scanner'
Ejemplo n.º 2
0
class VersionDiff(models.Model):
    objects = InheritanceManager()
    num_added = models.IntegerField()
    num_modified = models.IntegerField()
    num_removed = models.IntegerField()
    num_unchanged = models.IntegerField()
    COLS_FROM_TO = []
    COLS_CHANGE_COUNT = []

    @property
    def total(self):
        return self.num_added + self.num_modified + self.num_removed + self.num_unchanged

    @property
    def percent_added(self):
        return 100.0 * self.num_added / self.total

    @property
    def percent_modified(self):
        return 100.0 * self.num_modified / self.total

    @property
    def percent_removed(self):
        return 100.0 * self.num_removed / self.total

    @property
    def percent_unchanged(self):
        return 100.0 * self.num_unchanged / self.total

    @staticmethod
    def description(version_from, version_to):
        from_date = version_from.annotation_date.date()
        to_date = version_to.annotation_date.date()
        time_between = timesince(version_to.annotation_date,
                                 version_from.annotation_date)
        return f"{from_date} to {to_date} ({time_between})"

    def get_diff_sql(self, _select_columns):
        return NotImplementedError()

    def create_version_diffs(self):
        vg_column_prefix = self.VG_COLUMN_PREFIX
        cols_from_to = self.COLS_FROM_TO
        cols_change_count = self.COLS_CHANGE_COUNT
        columns = cols_from_to + cols_change_count
        ALIASES = ["v1", "v2"]

        def get_column_alias(alias, column):
            return f'"{alias}"."{column}"'

        alias_columns = defaultdict(list)
        counters_from_to = []
        counters_change = []
        for c in columns:
            for alias in ALIASES:
                column = get_column_alias(alias, c)
                alias_columns[alias].append(column)

            variant_column = f"{vg_column_prefix}__{c}"
            vgc = VariantGridColumn.objects.get(variant_column=variant_column)
            if c in cols_from_to:
                counters_from_to.append((c, vgc, defaultdict(Counter)))
            elif c in cols_change_count:
                # In a list so that we can alter the object rather than copies
                counters_change.append((c, vgc, [0]))

        select_columns = []
        for alias in ALIASES:  # Always add primary key
            select_columns.append(get_column_alias(alias, "id"))

        for ac in alias_columns.values():
            select_columns.extend(ac)

        sql = self.get_diff_sql(select_columns)
        cursor = connection.cursor()
        cursor.execute(sql)

        self.num_added = 0
        self.num_modified = 0
        self.num_removed = 0
        self.num_unchanged = 0

        for data in dictfetchall(cursor, column_names=select_columns):
            v1_id, v2_id = [data[k] for k in select_columns[:2]]
            # Could be modified
            a1 = ALIASES[0]
            a2 = ALIASES[1]
            v1_columns = alias_columns[a1]
            v2_columns = alias_columns[a2]

            v1 = [data[v] for v in v1_columns]
            v2 = [data[v] for v in v2_columns]
            modified = reduce(operator.or_, [a != b for a, b in zip(v1, v2)])

            if v1_id and not v2_id:
                self.num_removed += 1
            elif v2_id and not v1_id:
                self.num_added += 1
            else:
                if modified:
                    self.num_modified += 1
                else:
                    self.num_unchanged += 1

            for column, vgc, counters in counters_from_to:
                val_1 = data[get_column_alias(a1, column)]
                val_2 = data[get_column_alias(a2, column)]
                counters[val_1][val_2] += 1

            for column, vgc, count_list in counters_change:
                val_1 = data[get_column_alias(a1, column)]
                val_2 = data[get_column_alias(a2, column)]
                if val_1 != val_2:
                    count_list[0] += 1

        self.save()

        for column, vgc, count_list in counters_change:
            vdr = VersionDiffChangeCountResult(version_diff=self,
                                               vg_column=vgc,
                                               count=count_list[0])
            vdr.save()

        for column, vgc, counters in counters_from_to:
            for value_from, counter in counters.items():
                for value_to, count in counter.items():
                    vdr = VersionDiffFromToResult(version_diff=self,
                                                  vg_column=vgc,
                                                  value_from=value_from,
                                                  value_to=value_to,
                                                  count=count)
                    vdr.save()

    def get_vg_column(self, base_column):
        variant_column = f"{self.VG_COLUMN_PREFIX}__{base_column}"
        return VariantGridColumn.objects.get(variant_column=variant_column)

    def get_diff_results(self):
        results = defaultdict(list)
        for c in self.COLS_FROM_TO:
            variant_column = self.get_vg_column(c)
            df = self.get_column_version_diff_as_df(variant_column)
            results["cols_from_to"].append((variant_column, df))

        for c in self.COLS_CHANGE_COUNT:
            variant_column = self.get_vg_column(c)
            count = self.get_column_version_diff_change_count(variant_column)
            results["cols_change_count"].append((variant_column, count))

        return results

    def get_column_version_diff_as_df(self, variant_grid_column):
        qs = self.versiondifffromtoresult_set.filter(
            vg_column=variant_grid_column)
        data = defaultdict(dict)
        for value_from, value_to, count in qs.values_list(
                'value_from', 'value_to', 'count'):
            data[value_from][value_to] = count
        df = pd.DataFrame.from_dict(data).fillna(0)
        NO_ENTRY_DICT = {None: "No Entry"}
        return df.rename(index=NO_ENTRY_DICT, columns=NO_ENTRY_DICT)

    def get_column_version_diff_change_count(self, variant_grid_column):
        vd = self.versiondiffchangecountresult_set.get(
            vg_column=variant_grid_column)
        return vd.count
Ejemplo n.º 3
0
class Bookmark(models.Model):
    user = models.ForeignKey(get_user_model(), related_name='bookmark_contents')
    created = models.DateTimeField(default=timezone.now)
    objects = InheritanceManager()
Ejemplo n.º 4
0
class BuggyModel(models.Model):
    objects = InheritanceManager()

    name = models.CharField()
Ejemplo n.º 5
0
class FlagBase(models.Model):
    ''' This defines a condition which allows products or categories to
    be made visible, or be prevented from being visible.

    Attributes:
        description (str): A human-readable description that is used to
            identify the flag to staff in the admin interface. It's not seen
            anywhere else in Registrasion.

        condition (int): This determines the effect of this flag's condition
            being met. There are two types of condition:

            ``ENABLE_IF_TRUE`` conditions switch on the products and
            categories included under this flag if *any* such condition is met.

            ``DISABLE_IF_FALSE`` conditions *switch off* the products and
            categories included under this flag is any such condition
            *is not* met.

            If you have both types of conditions attached to a Product, every
            ``DISABLE_IF_FALSE`` condition must be met, along with one
            ``ENABLE_IF_TRUE`` condition.

        products ([inventory.Product, ...]):
            The Products affected by this flag.

        categories ([inventory.Category, ...]):
            The Categories whose Products are affected by this flag.
    '''

    objects = InheritanceManager()

    DISABLE_IF_FALSE = 1
    ENABLE_IF_TRUE = 2

    def __str__(self):
        return self.description

    def effects(self):
        ''' Returns all of the items affected by this condition. '''
        return itertools.chain(self.products.all(), self.categories.all())

    @property
    def is_disable_if_false(self):
        return self.condition == FlagBase.DISABLE_IF_FALSE

    @property
    def is_enable_if_true(self):
        return self.condition == FlagBase.ENABLE_IF_TRUE

    description = models.CharField(max_length=255)
    condition = models.IntegerField(
        default=ENABLE_IF_TRUE,
        choices=(
            (DISABLE_IF_FALSE, _("Disable if false")),
            (ENABLE_IF_TRUE, _("Enable if true")),
        ),
        help_text=_("If there is at least one 'disable if false' flag "
                    "defined on a product or category, all such flag "
                    " conditions must be met. If there is at least one "
                    "'enable if true' flag, at least one such condition must "
                    "be met. If both types of conditions exist on a product, "
                    "both of these rules apply."
                    ),
    )
    products = models.ManyToManyField(
        inventory.Product,
        blank=True,
        help_text=_("Products affected by this flag's condition."),
        related_name="flagbase_set",
    )
    categories = models.ManyToManyField(
        inventory.Category,
        blank=True,
        help_text=_("Categories whose products are affected by this flag's "
                    "condition."
                    ),
        related_name="flagbase_set",
    )
Ejemplo n.º 6
0
class Problem(models.Model):
    """Base class for problems, with common attributes and methods"""
    __INSERT_SEPARATION = "-- @new data base@"
    title_md = models.CharField(max_length=100, blank=True)
    title_html = models.CharField(max_length=200)
    text_md = models.TextField(max_length=5000, blank=True)
    text_html = models.TextField(max_length=10000)
    language = models.CharField(max_length=7,
                                choices=settings.LANGUAGES,
                                default=settings.LANGUAGE_CODE)
    create_sql = models.TextField(max_length=20000, blank=True)
    insert_sql = models.TextField(max_length=20000, blank=True)
    initial_db = JSONField(encoder=DjangoJSONEncoder,
                           default=None,
                           blank=True,
                           null=True)
    min_stmt = models.PositiveIntegerField(default=1)
    max_stmt = models.PositiveIntegerField(default=1)
    collection = models.ForeignKey(Collection, on_delete=models.CASCADE)
    author = models.ForeignKey(settings.AUTH_USER_MODEL,
                               null=True,
                               on_delete=models.SET_NULL)
    creation_date = models.DateTimeField(auto_now_add=True)
    position = models.PositiveIntegerField(default=1, null=False)
    # (Dirty) trick to upload ZIP files using the standard admin interface of Django
    zipfile = models.FileField(upload_to='problem_zips/',
                               default=None,
                               blank=True,
                               null=True)

    # To query Problem to obtain subclass objects with '.select_subclasses()'
    objects = InheritanceManager()

    def clean(self):
        """Check the number of statements and creates HTML versions from MarkDown"""
        super().clean()

        if self.min_stmt > self.max_stmt:
            raise ValidationError('Invalid statement range',
                                  code='invalid_stmt_range')

        self.title_html = markdown_to_html(self.title_md,
                                           remove_initial_p=True)
        self.text_html = markdown_to_html(self.text_md, remove_initial_p=False)

    def __str__(self):
        """String to show in the Admin interface"""
        return html.fromstring(self.title_html).text_content()

    def template(self):
        """Name of the HTML template used to show the problem"""
        raise NotImplementedError

    def judge(self, code, executor):
        """Assess the code with the user solution using a DB executor"""
        raise NotImplementedError

    def problem_type(self):
        """Return an enumeration ProblemType with the problem type"""
        raise NotImplementedError

    def solved_by_user(self, user) -> bool:
        """Whether user has solved the problem or not"""
        return Submission.objects.filter(
            user=user, problem=self, verdict_code=VerdictCode.AC).count() > 0

    def num_submissions_by_user(self, user):
        """Number of user submissions to the problem"""
        return Submission.objects.filter(problem=self, user=user).count()

    def solved_n_position(self, position):
        """User (non-staff and active) who solved the problem in 'position' position"""
        active_students = get_user_model().objects.filter(is_staff=False,
                                                          is_active=True)
        pks = Submission.objects.filter(problem=self, verdict_code=VerdictCode.AC, user__in=active_students) \
            .order_by('user', 'pk').distinct('user').values_list('pk', flat=True)
        subs = Submission.objects.filter(pk__in=pks).order_by('pk')[position -
                                                                    1:position]
        if len(subs) > 0 and subs[0] is not None:
            return subs[0].user
        return None

    def solved_first(self):
        """User (non-staff and active) who solved first"""
        return self.solved_n_position(1)

    def solved_second(self):
        """User (non-staff and active) who solved second"""
        return self.solved_n_position(2)

    def solved_third(self):
        """User (non-staff and active) who solved third"""
        return self.solved_n_position(3)

    def solved_position(self, user):
        """Position that user solved the problem (ignoring staff and inactive users). If not solved return None"""
        if self.solved_by_user(user):
            active_students = get_user_model().objects.filter(is_staff=False,
                                                              is_active=True)
            iterator = 1
            users_ac = (Submission.objects.filter(
                problem=self,
                user__in=active_students,
                verdict_code=VerdictCode.AC).order_by('pk', 'user').distinct(
                    'pk', 'user').values_list('user', flat=True))
            for users in users_ac:
                if users == user.pk:
                    return iterator
                iterator = iterator + 1
        return None

    def insert_sql_list(self):
        """List containing all sql inserts"""
        return self.insert_sql.split(self.__INSERT_SEPARATION)
Ejemplo n.º 7
0
class PaymentMethod(models.Model):
    payment_processor = PaymentProcessorField(
        choices=PaymentProcessorManager.get_choices(), blank=False)
    customer = models.ForeignKey(Customer)
    added_at = models.DateTimeField(default=timezone.now)
    verified_at = models.DateTimeField(null=True, blank=True)
    data = JSONField(blank=True, null=True)

    objects = InheritanceManager()

    class States(object):
        Uninitialized = 'uninitialized'
        Unverified = 'unverified'
        Enabled = 'enabled'
        Disabled = 'disabled'
        Removed = 'removed'

        Choices = ((Uninitialized, 'Uninitialized'),
                   (Unverified, 'Unverified'), (Enabled, 'Enabled'),
                   (Disabled, 'Disabled'), (Removed, 'Removed'))

        @classmethod
        def as_list(cls):
            return [choice[0] for choice in cls.Choices]

        @classmethod
        def allowed_initial_states(cls):
            return [cls.Uninitialized, cls.Unverified, cls.Enabled]

        @classmethod
        def invalid_initial_states(cls):
            return list(set(cls.as_list()) - set(cls.allowed_initial_states()))

    state = FSMField(choices=States.Choices, default=States.Uninitialized)
    state_transitions = {
        'initialize_unverified': {
            'source': States.Uninitialized,
            'target': States.Unverified
        },
        'initialize_enabled': {
            'source': States.Uninitialized,
            'target': States.Enabled
        },
        'verify': {
            'source': States.Unverified,
            'target': States.Enabled
        },
        'remove': {
            'source': [States.Enabled, States.Disabled, States.Unverified],
            'target': States.Removed
        },
        'disable': {
            'source': States.Enabled,
            'target': States.Disabled
        },
        'reenable': {
            'source': States.Disabled,
            'target': States.Enabled
        }
    }

    def __init__(self, *args, **kwargs):
        super(PaymentMethod, self).__init__(*args, **kwargs)

        if self.id:
            try:
                payment_method_class = self.payment_processor.payment_method_class

                if payment_method_class:
                    self.__class__ = payment_method_class
            except AttributeError:
                pass

    @transition(field='state', **state_transitions['initialize_unverified'])
    def initialize_unverified(self, initial_data=None):
        pass

    @transition(field='state', **state_transitions['initialize_enabled'])
    def initialize_enabled(self, initial_data=None):
        pass

    @transition(field='state', **state_transitions['verify'])
    def verify(self):
        pass

    @transition(field='state', **state_transitions['remove'])
    def remove(self):
        """
        Methods that implement this, need to remove the payment method from
        the real Payment Processor or raise TransitionNotAllowed
        """
        pass

    @transition(field='state', **state_transitions['disable'])
    def disable(self):
        pass

    @transition(field='state', **state_transitions['reenable'])
    def reenable(self):
        pass

    def delete(self, using=None):
        if not self.state == self.States.Uninitialized:
            self.remove()

        super(PaymentMethod, self).delete(using=using)

    def pay_billing_document(self, document):
        if self.state == self.States.Enabled:
            self.payment_processor.pay_billing_document(document, self)
        else:
            raise PaymentMethodInvalid

    def __unicode__(self):
        return u'{} - {}'.format(self.customer, self.payment_processor)
Ejemplo n.º 8
0
class Resource(models.Model):
    '''Represents a resource, with importance to a given task or processtask.

    Attributes:
        :id (int): Private sequential identificator
        :start_date (datetime): Creation date
        :latest_update (datetime): Date of latest update
        :removed (boolean): Logical indicator of removal status of this resource

    '''
    hash = models.CharField(max_length=50)
    ttype = models.CharField(max_length=100)
    create_date = models.DateTimeField(auto_now_add=True)
    latest_update = models.DateTimeField(auto_now=True)
    creator = models.ForeignKey(User)

    removed = models.BooleanField(default=False)
    # We need this to be able to properly guess the type
    objects = InheritanceManager()

    def clone(self):
        '''
            Clones a resource, creating a copy and returning it
        '''
        new_kwargs = dict([(fld.name, getattr(self, fld.name))
                           for fld in self._meta.fields
                           if fld.name != self._meta.pk.name])
        try:
            del new_kwargs['hash']
        except:
            pass

        return self.__class__.objects.create(**new_kwargs)

    def remove(self):
        '''
            Logically removes a Resource
        '''
        self.removed = True
        self.save()

    def link(self):
        '''
            Links a Resource to a Workflow. Until a Resource is linked he has no context.
            Unlinked resources will be periodically cleaned.
        '''
        pass

    @staticmethod
    def all(subclasses=True, creator=None):
        ''' Returns all valid resource instances (excluding logically removed)

        '''
        tmp = Resource.objects.filter(removed=False)

        if creator != None:
            tmp = tmp.filter(creator=creator)

        if subclasses:
            tmp = tmp.select_subclasses()

        return tmp

    def type(self):
        ''' Returns the specific resource type, polymorphically
        '''
        return self._meta.app_label + '.' + self.__class__.__name__

    def to_representation(self, instance):
        ''' Converts str to json for serialization.
        '''
        serializer = self.get_serializer()

        return serializer.to_representation(instance)

    def to_internal_value(self, instance):
        ''' Converts json to str for model saving.
        '''
        serializer = self.get_serializer()

        return serializer.to_internal_value(instance)

    @staticmethod
    def init_serializer(instance=None, data=None, many=False, partial=False):
        ''' Initializes a serializer able to process this specific type of Resource
            Each Resource child should specify this field.
        '''
        from .api import ResourceSerializer
        return ResourceSerializer(instance=instance,
                                  data=data,
                                  many=many,
                                  partial=partial)

    def get_serializer(self):
        ''' Returns a serializer to process this kind of Resource
        '''
        serializer_name = '__%s' % (self.type())
        serializer = None

        if hasattr(Resource, serializer_name):
            serializer = getattr(Resource, serializer_name)
        else:
            serializer = self.init_serializer()
            setattr(Resource, serializer_name, serializer)

        return serializer

    class Meta:
        ordering = ['-id']
Ejemplo n.º 9
0
class Widget(models.Model):
    """ Defines a UI widget and the source datatables
    """
    tables = models.ManyToManyField(Table)
    section = models.ForeignKey(Section)
    title = models.CharField(max_length=100)
    row = models.IntegerField()
    col = models.IntegerField()
    width = models.IntegerField(default=6)

    # setting height of 0 will let widget box auto-size to resulting data
    height = models.IntegerField(default=300)
    rows = models.IntegerField(default=-1)
    options = PickledObjectField()

    module = models.CharField(max_length=100)
    uiwidget = models.CharField(max_length=100)
    uioptions = PickledObjectField()

    # not globally unique, but should be sufficiently unique within a report
    slug = models.SlugField(max_length=100)

    # widget to be stacked below the previous widget on the same row
    stack_widget = models.BooleanField(default=False)

    objects = InheritanceManager()

    def __repr__(self):
        return '<Widget %s (%s)>' % (self.title, self.id)

    def __unicode__(self):
        return '<Widget %s (%s)>' % (self.title, self.id)

    def save(self, *args, **kwargs):
        self.slug = '%s-%d-%d' % (slugify(self.title), self.row, self.col)
        super(Widget, self).save(*args, **kwargs)

    @classmethod
    def create(cls, *args, **kwargs):
        options = kwargs.pop('options', None)
        table = kwargs.pop('table', None)

        w = Widget(*args, **kwargs)
        w.compute_row_col()

        if options:
            w.options = JsonDict(options)

        w.save()

        if table:
            w.tables.add(table)

        return w

    def get_definition(self, criteria):
        """Get dict of widget attributes for sending via JSON."""
        report = self.section.report

        widget_def = {
            "widgettype":
            self.widgettype().split("."),
            "posturl":
            reverse('widget-job-list',
                    args=(report.namespace, report.slug, self.slug)),
            "updateurl":
            reverse('widget-criteria',
                    args=(report.namespace, report.slug, self.slug)),
            "options":
            self.uioptions,
            "widgetid":
            self.id,
            "widgetslug":
            self.slug,
            "row":
            self.row,
            "width":
            self.width,
            "height":
            self.height,
            "criteria":
            criteria,
        }

        return widget_def

    def widgettype(self):
        return '%s.%s' % (self.module.split('.')[-1], self.uiwidget)

    def table(self, i=0):
        return self.tables.all()[i]

    def compute_row_col(self):
        rowmax = self.section.report.widgets().aggregate(Max('row'))
        row = rowmax['row__max']
        if row is None:
            row = 1
            col = 1
        elif self.stack_widget:
            # This widget needs to be stacked below the previous widget
            pre_w = self.section.report.widgets().order_by('-row', '-col')[0]
            if pre_w.width != self.width:
                raise ValueError("The stack widget with title '%s' should set "
                                 "with width %s." % (self.title, pre_w.width))
            elif pre_w.title.lower() == self.title.lower():
                raise ValueError("The stack widget title '%s' is the same as "
                                 "the previous widget, thus should be "
                                 "changed." % self.title)
            row = pre_w.row
            col = pre_w.col
        else:
            widthsum = (self.section.report.widgets().filter(
                row=row).aggregate(Sum('width')))
            width = widthsum['width__sum']
            if width + self.width > 12:
                row += 1
                col = 1
            else:
                col = width + 1

        self.row = row
        self.col = col

    def collect_fields(self):
        # Gather up all fields
        fields = OrderedDict()

        # All fields attached to the section's report
        for f in self.section.report.fields.all().order_by('id'):
            fields[f.keyword] = f

        # All fields attached to the section
        for f in self.section.fields.all().order_by('id'):
            if f.keyword not in fields:
                fields[f.keyword] = f

        # All fields attached to any Widget's Tables
        for w in self.section.widget_set.all().order_by('id'):
            for t in w.tables.all():
                for f in t.fields.all().order_by('id'):
                    if f.keyword not in fields:
                        fields[f.keyword] = f

        return fields
Ejemplo n.º 10
0
class TicketEvent(models.Model):
    objects = InheritanceManager()
    ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE)
    initiator = models.ForeignKey("User", on_delete=models.CASCADE, null=True)
    date_edited = models.DateTimeField(auto_now=True)
    date_created = models.DateTimeField(auto_now_add=True)
Ejemplo n.º 11
0
class Asset(TranslatedModel, LicensedModel, PublishedModel,
    TimestampedModel, AssetPermission):
    """A piece of content included in a story

    An asset could be an image, a block of text, an embedded resource
    represented by an HTML snippet or a media file.
    
    This is a base class that provides common metadata for the asset.
    However, it does not provide the fields that specify the content
    itself.  Also, to reduce the number of database tables and queries
    this model class does not provide translated metadata fields.  When
    creating an asset, one shouldn't instantiate this class, but instead
    use one of the model classes that inherits form Asset.

    """
    asset_id = UUIDField(auto=True)
    type = models.CharField(max_length=10, choices=ASSET_TYPES)
    attribution = models.TextField(blank=True)
    source_url = models.URLField(blank=True)
    """The URL where an asset originated.

    It could be used to store the canonical URL for a resource that is not
    yet oEmbedable or the canonical URL of an article or tweet where text 
    is quoted from.

    """
    owner = models.ForeignKey(User, related_name="assets", blank=True,
                              null=True)
    section_specific = models.BooleanField(default=False)
    datasets = models.ManyToManyField('DataSet', related_name='assets', 
                                      blank=True)
    asset_created = models.DateTimeField(blank=True, null=True)
    """Date/time the non-digital version of an asset was created

    For example, the data a photo was taken
    """

    translated_fields = ['title', 'caption']
    translation_class = AssetTranslation

    # Use InheritanceManager from django-model-utils to make
    # fetching of subclassed objects easier
    objects = InheritanceManager()

    def __unicode__(self):
        subclass_obj = Asset.objects.get_subclass(pk=self.pk)
        return subclass_obj.__unicode__()

    @models.permalink
    def get_absolute_url(self):
        return ('asset_detail', [str(self.asset_id)])

    def display_title(self):
        """
        Wrapper to handle displaying some kind of title when the
        the title field is blank 
        """
        # For now just call the __unicode__() method
        return unicode(self)

    def render(self, format='html'):
        """Render a viewable representation of an asset

        Arguments:
        format -- the format to render the asset. defaults to 'html' which
                  is presently the only available option.

        """
        try:
            return getattr(self, "render_" + format).__call__()
        except AttributeError:
            return self.__unicode__()

    def render_thumbnail(self, width=None, height=None, format='html',
                         **kwargs):
        """Render a thumbnail-sized viewable representation of an asset 

        Arguments:
        height -- Height of the thumbnail in pixels
        width  -- Width of the thumbnail in pixels
        format -- the format to render the asset. defaults to 'html' which
                  is presently the only available option.

        """
        return getattr(self, "render_thumbnail_" + format).__call__(
            width, height, **kwargs)

    def render_thumbnail_html(self, width=150, height=100, **kwargs):
        """
        Render HTML for a thumbnail-sized viewable representation of an 
        asset 

        This just provides a dummy placeholder and should be implemented
        classes that inherit from Asset.

        Arguments:
        height -- Height of the thumbnail in pixels
        width  -- Width of the thumbnail in pixels

        """
        html_class = kwargs.get('html_class', "")
        return mark_safe("<div class='asset-thumbnail %s' "
                "style='height: %dpx; width: %dpx'>Asset Thumbnail</div>" %
                (html_class, height, width))

    def get_thumbnail_url(self, width=150, height=100, **kwargs):
        """Return the URL of the Asset's thumbnail"""
        return None

    def dataset_html(self, label=_("Associated Datasets")):
        """Return an HTML list of associated datasets"""
        output = []
        if self.datasets.count():
            download_label = _("Download the data")
            output.append("<p class=\"datasets-label\">%s:</p>" %
                          label)
            output.append("<ul class=\"datasets\">")
            for dataset in self.datasets.select_subclasses():
                download_label = (_("Download the data") 
				  if dataset.links_to_file
				  else _("View the data"))
                output.append("<li>%s <a href=\"%s\">%s</a></li>" % 
                              (dataset.title, dataset.download_url(),
                               download_label))
            output.append("</ul>")
        return mark_safe(u'\n'.join(output))

    def full_caption_html(self, wrapper='figcaption'):
        """Return the caption and attribution text together"""
        output = ""
        if self.caption:
            output += "<div class='caption'>%s</div>" % (self.caption)
        if self.attribution:
            attribution = self.attribution
            if self.source_url:
                attribution = "<a href='%s'>%s</a>" % (self.source_url,
                    attribution)
            output += "<div class='attribution'>%s</div>" % (attribution)

        dataset_html = self.dataset_html()
        if dataset_html:
            output += dataset_html

        if output:
            output = '<%s>%s</%s>' % (wrapper, output, wrapper)

        return output
Ejemplo n.º 12
0
class TrackerModel(models.Model):
    '''This is the base Model that tracker types subclass.'''
    max_connections = models.IntegerField(
        blank=True,
        default=8,
        help_text=
        "This is the maximum number of simultaneous connections that our bug importer will make to the tracker server."
    )
    created_for_project = models.ForeignKey(
        'search.Project',
        null=True,
        help_text=
        'The project (if any) whose edit page caused the creation of this bug tracker model'
    )

    # Every subclass provides the following attributes. We set
    # them to None, here in the superclass.
    #
    # Additionally, we spell _form, _urlmodel, and _urlform with
    # underscores, and we put strings inside. Then, we access those
    # via get_form(), get_urlmodel(), and get_urlform(). This may
    # look weird, but it saves us from an otherwise-painful circular
    # import situation.
    short_name = None
    namestr = None
    _form = None
    _urlmodel = None
    _urlform = None

    def importable_or_none(name):
        def actual_function(cls, name=name):
            value = getattr(cls, name)
            if value is None:
                return None

            module_name, member_name = value.rsplit('.', 1)
            module = importlib.import_module(module_name)
            return getattr(module, member_name)

        return actual_function

    get_form = classmethod(importable_or_none('_form'))
    get_urlmodel = classmethod(importable_or_none('_urlmodel'))
    get_urlform = classmethod(importable_or_none('_urlform'))

    # This optional attribute specifies a class name, which is intepreted as
    # part of the mysite.customs.core_bugimporters module.
    #
    # If the class is specified, we will use custom code from that class
    # when doing bug parsing.
    custom_parser = models.CharField(
        max_length=200,
        blank=True,
        default='',
        help_text=
        '(For use by OpenHatch admins) Choose a custom bug parser class for the tracker'
    )

    objects = InheritanceManager()

    def as_dict(self):
        # First, add our data
        out_dict = django.forms.models.model_to_dict(self)

        # Then, indicate to downstream what kind of bug importer we are
        CLASS_NAME2SIMPLE_NAME = {
            mysite.customs.models.BugzillaTrackerModel: 'bugzilla',
            mysite.customs.models.GitHubTrackerModel: 'github',
            mysite.customs.models.GoogleTrackerModel: 'google',
            mysite.customs.models.JiraTrackerModel: 'jira',
            mysite.customs.models.RoundupTrackerModel: 'roundup',
            mysite.customs.models.TracTrackerModel: 'trac',
            mysite.customs.models.LaunchpadTrackerModel: 'launchpad',
            mysite.customs.models.TigrisTrackerModel: 'tigris',
        }
        out_dict['bugimporter'] = CLASS_NAME2SIMPLE_NAME[self.__class__]

        # Then, remove fields that we don't care about
        BLACKLISTED_FIELDS = set([
            'id',  # This is not needed by the importer
            'trackermodel_ptr',  # This is not needed by the importer
            'created_for_project',  # Not needed by importer either
            'old_trac',  # This is useless
            'max_connections',  # This is useless
        ])

        for field in BLACKLISTED_FIELDS:
            if field in out_dict:
                del out_dict[field]

        # Add a list of our queries.
        # This permits oh-bugimporters to go to the 'net and query the tracker
        # for new bugs that correspond to this bug tracker.
        query_urls = []
        for querymodel in TrackerQueryModel.__subclasses__():
            queries = querymodel.objects.filter(tracker=self)
            query_urls.extend([q.get_query_url() for q in queries])
        out_dict['queries'] = query_urls

        # Add a list of bug URLs we're responsible for.
        # This permits oh-bugimporters to go to the 'net and refresh each bug.
        # It is essential because otherwise, when a bug falls out of a query
        # (if, for example, it becomes 'resolved' and the query only looks for
        # bugs that need fixing), we would not get up-to-date information about
        # the bug.
        out_dict['existing_bug_urls'] = list(
            mysite.search.models.Bug.all_bugs.filter(
                tracker_id=self.id).values_list('canonical_bug_link',
                                                flat=True))

        # Some subclasses will add a get_older_bug_data value. This generic
        # method supports that by adding that key, and setting it to None.
        out_dict['get_older_bug_data'] = None

        return out_dict

    def get_edit_url(self):
        '''This method returns the URL you can use to access this tracker's edit
        link.

        It is part of this superclass so that derived classes can use the
        functionality without implementing it themselves. It relies on
        the subclasses having a short_name attribute.'''

        return reverse('mysite.customs.views.edit_tracker',
                       kwargs={
                           'tracker_id': self.id,
                           'tracker_type': self.short_name,
                           'tracker_name': self.tracker_name
                       })

    def get_base_url(self):
        # Implement this in a subclass
        raise NotImplementedError

    @staticmethod
    def get_by_name(tracker_model_name):
        '''This returns the right TrackerModel by looping
        across all the subclasses and returning the one that
        has the desired short_name.'''
        for candidate in TrackerModel.__subclasses__():
            if candidate.short_name == tracker_model_name:
                return candidate
        raise ValueError("No TrackerModel known by name: %s" %
                         (tracker_model_name, ))

    @classmethod
    def get_instance_by_name(cls, tracker_name):
        '''This returns the instance of a subclass of TrackerModel,
        if any, that has its tracker_name field set to the provided
        value.

        This is necessary because tracker_name is defined by each of
        the subclasses, rather than by this class in particular.'''
        query_parts = []
        for subclass in cls.__subclasses__():
            name = subclass.__name__.lower()
            query_as_dict = {name + '__tracker_name': tracker_name}
            query_parts.append(Q(**query_as_dict))

        def _pipe_things(a, b):
            return a | b

        joined = reduce(_pipe_things, query_parts)
        return cls.objects.select_subclasses().get(joined)

    @classmethod
    def get_instance_by_id(cls, tracker_name):
        query_parts = []
        for subclass in cls.__subclasses__():
            name = subclass.__name__.lower()
            query_as_dict = {name + '__pk': tracker_name}
            query_parts.append(Q(**query_as_dict))

        def _pipe_things(a, b):
            return a | b

        joined = reduce(_pipe_things, query_parts)
        return cls.objects.select_subclasses().get(joined)
Ejemplo n.º 13
0
class Comment(models.Model):
    """Comment in forum, articles, tutorial, chapter, etc."""
    class Meta:
        verbose_name = 'Commentaire'
        verbose_name_plural = 'Commentaires'

    objects = InheritanceManager()

    author = models.ForeignKey(User,
                               verbose_name='Auteur',
                               related_name='comments',
                               db_index=True)
    editor = models.ForeignKey(User,
                               verbose_name='Editeur',
                               related_name='comments-editor+',
                               null=True,
                               blank=True)
    ip_address = models.CharField('Adresse IP de l\'auteur ', max_length=39)

    position = models.IntegerField('Position', db_index=True)

    text = models.TextField('Texte')
    text_html = models.TextField('Texte en Html')

    like = models.IntegerField('Likes', default=0)
    dislike = models.IntegerField('Dislikes', default=0)

    pubdate = models.DateTimeField('Date de publication',
                                   auto_now_add=True,
                                   db_index=True)
    update = models.DateTimeField('Date d\'édition', null=True, blank=True)
    update_index_date = models.DateTimeField(
        'Date de dernière modification pour la réindexation partielle',
        auto_now=True,
        db_index=True)

    is_visible = models.BooleanField('Est visible', default=True)
    text_hidden = models.CharField('Texte de masquage ',
                                   max_length=80,
                                   default='')

    hat = models.ForeignKey(Hat,
                            verbose_name='Casquette',
                            on_delete=models.SET_NULL,
                            related_name='comments',
                            blank=True,
                            null=True)

    def update_content(self, text, on_error=None):
        _, old_metadata, _ = render_markdown(self.text)
        html, metadata, messages = render_markdown(text, on_error=on_error)
        self.text = text
        self.text_html = html
        self.save()
        all_the_pings = list(
            filter(lambda user_name: user_name != self.author.username,
                   metadata.get('ping', [])))
        all_the_pings = list(
            set(all_the_pings) - set(old_metadata.get('ping', [])))
        max_ping_count = settings.ZDS_APP['comment']['max_pings']
        first_pings = all_the_pings[:max_ping_count]
        for username in first_pings:
            pinged_user = User.objects.filter(username=username).first()
            if not pinged_user:
                continue
            signals.new_content.send(sender=self.__class__,
                                     instance=self,
                                     user=pinged_user)
        unpinged_usernames = set(old_metadata.get('ping',
                                                  [])) - set(all_the_pings)
        unpinged_users = User.objects.filter(
            username__in=list(unpinged_usernames))
        for unpinged_user in unpinged_users:
            signals.unsubscribe.send(self.author,
                                     instance=self,
                                     user=unpinged_user)

    def hide_comment_by_user(self, user, text_hidden):
        """Hide a comment and save it

        :param user: the user that hid the comment
        :param text_hidden: the hide reason
        :return:
        """
        self.is_visible = False
        self.text_hidden = text_hidden
        self.editor = user
        self.save()

    def get_user_vote(self, user):
        """ Get a user vote (like, dislike or neutral) """
        if user.is_authenticated():
            try:
                user_vote = 'like' if CommentVote.objects.get(
                    user=user, comment=self).positive else 'dislike'
            except CommentVote.DoesNotExist:
                user_vote = 'neutral'
        else:
            user_vote = 'neutral'

        return user_vote

    def set_user_vote(self, user, vote):
        """ Set a user vote (like, dislike or neutral) """
        if vote == 'neutral':
            CommentVote.objects.filter(user=user, comment=self).delete()
        else:
            CommentVote.objects.update_or_create(
                user=user,
                comment=self,
                defaults={'positive': (vote == 'like')})

        self.like = CommentVote.objects.filter(positive=True,
                                               comment=self).count()
        self.dislike = CommentVote.objects.filter(positive=False,
                                                  comment=self).count()

    def get_votes(self, type=None):
        """ Get the non-anonymous votes """
        if not hasattr(self, 'votes'):
            self.votes = CommentVote.objects.filter(
                comment=self,
                id__gt=settings.VOTES_ID_LIMIT).select_related('user').all()

        return self.votes

    def get_likers(self):
        """ Get the list of the users that liked this Comment """
        return [vote.user for vote in self.get_votes() if vote.positive]

    def get_dislikers(self):
        """ Get the list of the users that disliked this Comment """
        return [vote.user for vote in self.get_votes() if not vote.positive]

    def get_absolute_url(self):
        return Comment.objects.get_subclass(id=self.id).get_absolute_url()

    def __str__(self):
        return 'Comment by {}'.format(self.author.username)
Ejemplo n.º 14
0
class Status(OrderedCollectionPageMixin, BookWyrmModel):
    """any post, like a reply to a review, etc"""

    user = fields.ForeignKey("User",
                             on_delete=models.PROTECT,
                             activitypub_field="attributedTo")
    content = fields.HtmlField(blank=True, null=True)
    raw_content = models.TextField(blank=True, null=True)
    mention_users = fields.TagField("User", related_name="mention_user")
    mention_books = fields.TagField("Edition", related_name="mention_book")
    local = models.BooleanField(default=True)
    content_warning = fields.CharField(max_length=500,
                                       blank=True,
                                       null=True,
                                       activitypub_field="summary")
    privacy = fields.PrivacyField(max_length=255)
    sensitive = fields.BooleanField(default=False)
    # created date is different than publish date because of federated posts
    published_date = fields.DateTimeField(default=timezone.now,
                                          activitypub_field="published")
    edited_date = fields.DateTimeField(blank=True,
                                       null=True,
                                       activitypub_field="updated")
    deleted = models.BooleanField(default=False)
    deleted_date = models.DateTimeField(blank=True, null=True)
    favorites = models.ManyToManyField(
        "User",
        symmetrical=False,
        through="Favorite",
        through_fields=("status", "user"),
        related_name="user_favorites",
    )
    reply_parent = fields.ForeignKey(
        "self",
        null=True,
        on_delete=models.PROTECT,
        activitypub_field="inReplyTo",
    )
    thread_id = models.IntegerField(blank=True, null=True)
    objects = InheritanceManager()

    activity_serializer = activitypub.Note
    serialize_reverse_fields = [("attachments", "attachment", "id")]
    deserialize_reverse_fields = [("attachments", "attachment")]

    class Meta:
        """default sorting"""

        ordering = ("-published_date", )

    def save(self, *args, **kwargs):
        """save and notify"""
        if self.reply_parent:
            self.thread_id = self.reply_parent.thread_id or self.reply_parent.id

        super().save(*args, **kwargs)

        if not self.reply_parent:
            self.thread_id = self.id

        super().save(broadcast=False, update_fields=["thread_id"])

    def delete(self, *args, **kwargs):  # pylint: disable=unused-argument
        """ "delete" a status"""
        if hasattr(self, "boosted_status"):
            # okay but if it's a boost really delete it
            super().delete(*args, **kwargs)
            return
        self.deleted = True
        # clear user content
        self.content = None
        if hasattr(self, "quotation"):
            self.quotation = None  # pylint: disable=attribute-defined-outside-init
        self.deleted_date = timezone.now()
        self.save()

    @property
    def recipients(self):
        """tagged users who definitely need to get this status in broadcast"""
        mentions = [u for u in self.mention_users.all() if not u.local]
        if (hasattr(self, "reply_parent") and self.reply_parent
                and not self.reply_parent.user.local):
            mentions.append(self.reply_parent.user)
        return list(set(mentions))

    @classmethod
    def ignore_activity(cls, activity):  # pylint: disable=too-many-return-statements
        """keep notes if they are replies to existing statuses"""
        if activity.type == "Announce":
            try:
                boosted = activitypub.resolve_remote_id(activity.object,
                                                        get_activity=True)
            except activitypub.ActivitySerializerError:
                # if we can't load the status, definitely ignore it
                return True
            # keep the boost if we would keep the status
            return cls.ignore_activity(boosted)

        # keep if it if it's a custom type
        if activity.type != "Note":
            return False
        # keep it if it's a reply to an existing status
        if cls.objects.filter(remote_id=activity.inReplyTo).exists():
            return False

        # keep notes if they mention local users
        if activity.tag == MISSING or activity.tag is None:
            return True
        tags = [l["href"] for l in activity.tag if l["type"] == "Mention"]
        user_model = apps.get_model("bookwyrm.User", require_ready=True)
        for tag in tags:
            if user_model.objects.filter(remote_id=tag, local=True).exists():
                # we found a mention of a known use boost
                return False
        return True

    @classmethod
    def replies(cls, status):
        """load all replies to a status. idk if there's a better way
        to write this so it's just a property"""
        return (cls.objects.filter(
            reply_parent=status).select_subclasses().order_by("published_date")
                )

    @property
    def status_type(self):
        """expose the type of status for the ui using activity type"""
        return self.activity_serializer.__name__

    @property
    def boostable(self):
        """you can't boost dms"""
        return self.privacy in ["unlisted", "public"]

    def to_replies(self, **kwargs):
        """helper function for loading AP serialized replies to a status"""
        return self.to_ordered_collection(
            self.replies(self),
            remote_id=f"{self.remote_id}/replies",
            collection_only=True,
            **kwargs,
        ).serialize()

    def to_activity_dataclass(self, pure=False):  # pylint: disable=arguments-differ
        """return tombstone if the status is deleted"""
        if self.deleted:
            return activitypub.Tombstone(
                id=self.remote_id,
                url=self.remote_id,
                deleted=self.deleted_date.isoformat(),
                published=self.deleted_date.isoformat(),
            )
        activity = ActivitypubMixin.to_activity_dataclass(self)
        activity.replies = self.to_replies()

        # "pure" serialization for non-bookwyrm instances
        if pure and hasattr(self, "pure_content"):
            activity.content = self.pure_content
            if hasattr(activity, "name"):
                activity.name = self.pure_name
            activity.type = self.pure_type
            book = getattr(self, "book", None)
            books = [book] if book else []
            books += list(self.mention_books.all())
            if len(books) == 1 and getattr(books[0], "preview_image", None):
                covers = [
                    activitypub.Document(
                        url=fields.get_absolute_url(books[0].preview_image),
                        name=books[0].alt_text,
                    )
                ]
            else:
                covers = [
                    activitypub.Document(
                        url=fields.get_absolute_url(b.cover),
                        name=b.alt_text,
                    ) for b in books if b and b.cover
                ]
            activity.attachment = covers
        return activity

    def to_activity(self, pure=False):  # pylint: disable=arguments-differ
        """json serialized activitypub class"""
        return self.to_activity_dataclass(pure=pure).serialize()

    def raise_not_editable(self, viewer):
        """certain types of status aren't editable"""
        # first, the standard raise
        super().raise_not_editable(viewer)
        if isinstance(self, (GeneratedNote, ReviewRating)):
            raise PermissionDenied()

    @classmethod
    def privacy_filter(cls, viewer, privacy_levels=None):
        queryset = super().privacy_filter(viewer,
                                          privacy_levels=privacy_levels)
        return queryset.filter(deleted=False)

    @classmethod
    def direct_filter(cls, queryset, viewer):
        """Overridden filter for "direct" privacy level"""
        return queryset.exclude(~Q(Q(user=viewer) | Q(mention_users=viewer)),
                                privacy="direct")

    @classmethod
    def followers_filter(cls, queryset, viewer):
        """Override-able filter for "followers" privacy level"""
        return queryset.exclude(
            ~Q(  # not yourself, a follower, or someone who is tagged
                Q(user__followers=viewer) | Q(user=viewer)
                | Q(mention_users=viewer)),
            privacy="followers",  # and the status is followers only
        )
Ejemplo n.º 15
0
class ProposalBase(models.Model):

    objects = InheritanceManager()

    kind = models.ForeignKey(ProposalKind)

    title = models.CharField(_("Title"), max_length=100)
    description = models.TextField(
        _("Description"),
        max_length=
        200,  # @@@ need to enforce 400 in UI <= Can not change? I did it to 200.
        help_text=_("Please write up to 100 words. "
                    "This is published pamphlet when it is accepted."))
    abstract = models.TextField(
        _("Details Abstract"),
        help_text=_(
            "Please write detailed contents of your presentation to a maximum extent. "
            "This is published web site when it is accepted."))
    additional_notes = models.TextField(
        _("Additional Notes"),
        blank=True,
        help_text=_("Anything else you'd like the program committee to know "
                    "when making their selection: your past speaking "
                    "experience, open source community experience, etc. "
                    "This is not published. it is referenced by review."))
    submitted = models.DateTimeField(
        default=datetime.datetime.now,
        editable=False,
    )
    speaker = models.ForeignKey("speakers.Speaker", related_name="proposals")
    additional_speakers = models.ManyToManyField("speakers.Speaker",
                                                 through="AdditionalSpeaker",
                                                 blank=True)
    cancelled = models.BooleanField(default=False)
    tags = TaggableManager(blank=True)
    language = models.CharField(
        max_length=2,
        verbose_name=_("Language"),
        default=settings.LANGUAGES[0][0],
        choices=settings.LANGUAGES,
    )

    def __unicode__(self):
        return self.title

    def can_edit(self):
        if hasattr(self, "presentation") and self.presentation:
            return False
        else:
            return True

    def get_tags_display(self):
        # No idea why django-taggit doesn't offer this itself
        return u", ".join(tag.name for tag in self.tags.all())

    @property
    def section(self):
        return self.kind.section

    @property
    def speaker_email(self):
        return self.speaker.email

    @property
    def number(self):
        return str(self.pk).zfill(3)

    @property
    def status(self):
        try:
            return self.result.status
        except ObjectDoesNotExist:
            return 'undecided'

    def as_dict(self, details=False):
        """Return a dictionary representation of this proposal."""

        # Put together the base dict.
        answer = {
            'id': self.id,
            'speakers': [i.as_dict for i in self.speakers()],
            'status': self.status,
            'title': self.title,
        }

        # Include details iff they're requested.
        if details:
            answer['details'] = {
                'abstract': self.abstract,
                'description': self.description,
                'notes': self.additional_notes,
            }

            # If there is extra data that has been set, include it also.
            try:
                answer['extra'] = json.loads(self.data.data)
            except ObjectDoesNotExist:
                pass

        # Return the answer.
        return answer

    def speakers(self):
        yield self.speaker
        for speaker in self.additional_speakers.exclude(
                additionalspeaker__status=AdditionalSpeaker.
                SPEAKING_STATUS_DECLINED):
            yield speaker

    def notification_email_context(self):
        return {
            "title": self.title,
            "speaker": self.speaker.name,
            "speakers": ', '.join([x.name for x in self.speakers()]),
            "kind": self.kind.name,
        }
Ejemplo n.º 16
0
class InheritanceManagerTestChild1(InheritanceManagerTestParent):
    non_related_field_using_descriptor_2 = models.FileField(upload_to="test")
    normal_field_2 = models.TextField()
    objects = InheritanceManager()
Ejemplo n.º 17
0
class Project(models.Model):
    """ Base class for project types

    data_project stores a validated JSON representation of the project
    get_dataproject() method returns the python dict representation of the project


    """
    owner = models.ForeignKey('authosm.OsmUser', db_column='owner')
    name = models.CharField(max_length=20, default='')
    created_date = models.DateTimeField(default=timezone.now)
    updated_date = models.DateTimeField(default=timezone.now,
                                        blank=True,
                                        null=True)
    info = models.TextField(default='No info')
    data_project = jsonfield.JSONField(default={})
    """Stores a validated JSON representation of the project"""

    validated = models.BooleanField(default=False)

    #InheritanceManager
    objects = InheritanceManager()

    @classmethod
    def get_project_types(cls):
        global project_types
        return project_types

    @classmethod
    def add_project_type(cls, type, my_class):
        global project_types
        project_types[type] = my_class

    @classmethod
    def create_project(cls, name, user, validated, info, data_project):
        project = cls.objects.create(name=name,
                                     owner=user,
                                     validated=False,
                                     info=info,
                                     data_project=data_project)
        return project

    @classmethod
    def get_graph_model(cls, file_path):
        """Returns the model of the graph of the project type as a yaml object

        Returns an empty dict if there is no file with the model
        """
        # file_path = GRAPH_MODEL_FULL_NAME
        graph_model = {}
        try:
            graph_model = Util.loadyamlfile(file_path)
        except Exception as e:
            log.exception(e)
            pass
        return graph_model

    def get_type(self):
        return "Base"

    #@classmethod
    def get_dataproject(self):
        """ Return the python dict representation of the project data

        """
        #current_data = json.loads(self.data_project)
        current_data = Util.json_loads_byteified(self.data_project)

        return current_data

    #@classmethod
    def get_overview_data(self):
        result = {
            'owner': self.owner,
            'name': self.name,
            'updated_date': self.updated_date,
            'info': self.info,
            'validated': self.validated
        }

        return result

    def set_data_project(self, new_data, validated):
        self.data_project = new_data
        self.set_validated(validated)
        self.update()

    def update(self):
        self.updated_date = timezone.now()
        self.save()

    def __str__(self):
        return self.name

    def edit_graph_positions(self, positions):
        # print positions
        try:
            current_data = json.loads(self.data_project)
            if 'positions' not in current_data:
                current_data['positions'] = {}
            if 'vertices' not in current_data['positions']:
                current_data['positions']['vertices'] = {}
            if 'vertices' in positions:
                current_data['positions']['vertices'].update(
                    positions['vertices'])
            self.data_project = current_data
            self.update()
            result = True
        except Exception as e:
            log.debug(e)
            result = False
        return result

    def get_descriptors(self, type_descriptor):
        """Returns all descriptors of a given type"""

        try:
            current_data = json.loads(self.data_project)
            result = current_data[type_descriptor]
        except Exception as e:
            log.debug(e)
            result = {}
        return result

    def get_descriptor(self, descriptor_id, type_descriptor):
        """Returns a specific descriptor"""

        try:
            current_data = json.loads(self.data_project)
            result = current_data[type_descriptor][descriptor_id]
            print descriptor_id, type_descriptor, result
        except Exception as e:
            log.debug(e)
            result = {}

        return result

    def delete_descriptor(self, type_descriptor, descriptor_id):
        try:
            log.debug('delete descriptor' + descriptor_id + ' ' +
                      type_descriptor)
            current_data = json.loads(self.data_project)
            del (current_data[type_descriptor][descriptor_id])
            self.data_project = current_data
            self.update()
            result = True
        except Exception as e:
            log.debug(e)
            result = False
        return result

    def clone_descriptor(self, type_descriptor, descriptor_id, new_id):
        try:
            current_data = json.loads(self.data_project)
            descriptor = current_data[type_descriptor][descriptor_id]
            new_descriptor = self.get_clone_descriptor(descriptor,
                                                       type_descriptor, new_id)
            current_data[type_descriptor][new_id] = new_descriptor
            self.data_project = current_data
            self.update()
            result = True
        except Exception as e:
            log.debug(e)
            result = False
        return result

    def edit_descriptor(self, type_descriptor, descriptor_id, new_data,
                        data_type):
        try:

            ##FIXME questa parte va completamente rivista cosi' ha varie lacune
            #log.info('editing ',+ descriptor_id + ' ' + type_descriptor + ' ' + data_type)
            current_data = json.loads(self.data_project)
            new_descriptor = new_data
            if data_type == 'json':
                new_descriptor = json.loads(new_data)
            elif data_type == 'yaml':
                yaml_object = yaml.load(new_data)
                new_descriptor = json.loads(Util.yaml2json(yaml_object))
            if type_descriptor != 'click' and type_descriptor != 'oshi' and type_descriptor != 'cran':
                reference_schema = self.get_json_schema_by_type(
                    type_descriptor)
                Util.validate_json_schema(reference_schema, new_descriptor)
            current_data[type_descriptor][descriptor_id] = new_descriptor
            self.data_project = current_data
            self.update()
            result = True
        except Exception as e:
            log.debug(e)
            result = False
        return result

    def get_zip_archive(self):
        in_memory = StringIO()
        try:
            current_data = json.loads(self.data_project)
            zip = zipfile.ZipFile(in_memory, "w", zipfile.ZIP_DEFLATED)
            for desc_type in current_data:
                for current_desc in current_data[desc_type]:
                    zip.writestr(
                        current_desc + '.json',
                        json.dumps(current_data[desc_type][current_desc]))

            zip.close()
        except Exception as e:
            log.debug(e)

        in_memory.flush()
        return in_memory

    def get_positions(self):
        """Returns the positions of nodes"""
        try:
            current_data = json.loads(self.data_project)
            positions = {}
            if 'positions' in current_data:
                positions = current_data['positions']
        except Exception as e:
            log.debug(e)

        return positions

    def get_deployment_descriptor(self, **kwargs):
        """Returns the deployment descriptor"""
        raise NotImplementedError

    def get_node_overview(self, **kwargs):
        """Returns the node overview"""
        raise NotImplementedError

    def get_all_ns_descriptors(self, nsd_id):
        raise NotImplementedError

    def translate_push_ns_on_repository(self, translator, nsd_id, repository,
                                        **kwargs):
        raise NotImplementedError
Ejemplo n.º 18
0
class LineItem(models.Model):
    """An individual item that is either in a shopping cart or on an order.

    This model doesn't do anything by itself; you'll need to subclass it as
    described in the :doc:`Getting Started Guide <backend>`.
    """
    cart = models.ForeignKey(Cart,
                             related_name='items',
                             blank=True,
                             null=True,
                             on_delete=models.PROTECT)
    order = models.ForeignKey(Order,
                              related_name='items',
                              blank=True,
                              null=True,
                              on_delete=models.CASCADE)
    total_when_charged = models.DecimalField(max_digits=7,
                                             decimal_places=2,
                                             blank=True,
                                             null=True)

    objects = InheritanceManager()

    class Meta:
        # Because IDs auto increment, ordering by ID has the same effect as
        # ordering by date added, but we don't have to store the date
        ordering = ('id', )

    @property
    def total(self):
        """The total cost for this line item.

        Returns the total actually charged to the customer if this item
        is attached to an :class:`~lorikeet.models.Order`, or calls
        :func:`~lorikeet.models.LineItem.get_total` otherwise.
        """
        if self.order_id:
            return self.total_when_charged
        return self.get_total()

    def get_total(self):
        """Returns the total amount to charge on this LineItem.

        By default this raises ``NotImplemented``; subclasses of this
        class need to override this.

        If you want to know the total for this line item from your own
        code, use the :func:`~lorikeet.models.LineItem.total` property
        rather than calling this function.
        """
        raise NotImplementedError(
            "Provide a get_total method in your LineItem "
            "subclass {}.".format(self.__class__.__name__))

    def save(self, *args, **kwargs):
        if self.order is not None and not getattr(self, '_new_order'):
            raise ValueError("Cannot modify a cart item attached to an order.")
        return super().save(*args, **kwargs)

    def check_complete(self, for_checkout=False):
        """Checks that this line item is ready to be checked out.

        This method should raise
        :class:`~lorikeet.exceptions.IncompleteCartError` if the line
        item is not ready to be checked out (e.g. there is insufficient
        stock in inventory to fulfil this line item). By default it does
        nothing.

        :param for_checkout: Set to ``True`` when the cart is about to
            be checked out. See the documentation for
            :meth:`prepare_for_checkout` for more details.
            is going to be called within the current transaction, so you
            should use things like
            `select_for_update <https://docs.djangoproject.com/en/1.10/ref/models/querysets/#select-for-update>`_.
        :type for_checkout: bool
        """

    def prepare_for_checkout(self):
        """Prepare this line item for checkout.
Ejemplo n.º 19
0
class ProposalBase(models.Model):

    objects = InheritanceManager()

    kind = models.ForeignKey(ProposalKind)

    title = models.CharField(max_length=100)
    description = models.TextField(
        _("Brief Description"),
        max_length=400,  # @@@ need to enforce 400 in UI
        help_text=_(
            "If your proposal is accepted this will be made public and printed in the "
            "program. Should be one paragraph, maximum 400 characters."))
    abstract = models.TextField(
        _("Detailed Abstract"),
        help_text=
        _("Detailed outline. Will be made public if your proposal is accepted."
          ))
    additional_notes = models.TextField(
        blank=True,
        help_text=_(
            "Anything else you'd like the program committee to know when making their "
            "selection: your past experience, etc. This is not made public."))
    submitted = models.DateTimeField(
        default=now,
        editable=False,
    )
    speaker = models.ForeignKey(Speaker, related_name="proposals")
    additional_speakers = models.ManyToManyField(Speaker,
                                                 through="AdditionalSpeaker",
                                                 blank=True)
    cancelled = models.BooleanField(default=False)

    def can_edit(self):
        return True

    @property
    def section(self):
        return self.kind.section

    @property
    def speaker_email(self):
        return self.speaker.email

    @property
    def number(self):
        return str(self.pk).zfill(3)

    def speakers(self):
        yield self.speaker
        speakers = self.additional_speakers.exclude(
            additionalspeaker__status=AdditionalSpeaker.
            SPEAKING_STATUS_DECLINED)
        for speaker in speakers:
            yield speaker

    def notification_email_context(self):
        return {
            "title": self.title,
            "speaker": self.speaker.name,
            "kind": self.kind.name,
        }
Ejemplo n.º 20
0
class Adjustment(models.Model):
    """An adjustment to the total on a cart.

    Subclass this model only for adjustments that users can add to their carts
    (e.g. discount codes).

    This model doesn't do anything by itself; you'll need to subclass it.
    """
    cart = models.ForeignKey(Cart,
                             related_name='adjustments',
                             blank=True,
                             null=True,
                             on_delete=models.CASCADE)
    order = models.ForeignKey(Order,
                              related_name='adjustments',
                              blank=True,
                              null=True,
                              on_delete=models.CASCADE)
    total_when_charged = models.DecimalField(max_digits=7,
                                             decimal_places=2,
                                             blank=True,
                                             null=True)

    objects = InheritanceManager()

    @property
    def total(self):
        """The total cost for this line item.

        Returns the total actually charged to the customer if this
        adjustment is attached to an :class:`~lorikeet.models.Order`, or
        calls :func:`~lorikeet.models.Adjustment.get_total` otherwise.
        """
        if self.order_id:
            return self.total_when_charged
        return self.get_total()

    def get_total(self, subtotal=None):
        """Returns the total adjustment to make to the cart.

        By default this raises :class:`NotImplementedError`; subclasses will
        need to override this.

        If you want to know the total for this adjustment from your own
        code, use the :func:`~lorikeet.models.Adjustment.total` property
        rather than calling this function.

        :param subtotal: The subtotal of all line items, which is passed in
            as a convenience.
        :type subtotal: decimal.Decimal
        :return: The amount to add to the cart. This value can be
            (and in most cases, will be) negative, in order to represent a
            discount.
        :rtype: decimal.Decimal
        """
        raise NotImplementedError("Provide a get_total method in your "
                                  "Adjustment subclass {}.".format(
                                      self.__class__.__name__))

    def check_complete(self, for_checkout=False):
        """Checks that this adjustment is ready to be checked out.

        This method should raise
        :class:`~lorikeet.exceptions.IncompleteCartError` if the line
        item is not ready to be checked out (e.g. there is insufficient
        stock in inventory to fulfil this line item). By default it does
        nothing.

        :param for_checkout: Set to ``True`` when the cart is about to
            be checked out. See the documentation for
            :meth:`prepare_for_checkout` for more details.
            is going to be called within the current transaction, so you
            should use things like
            `select_for_update <https://docs.djangoproject.com/en/1.10/ref/models/querysets/#select-for-update>`_.
        :type for_checkout: bool
        """

    def prepare_for_checkout(self):
        """Prepare this adjustment for checkout.
Ejemplo n.º 21
0
class Question(models.Model):
    """
    Base class for all question types.
    Shared properties placed here.
    """

    quiz = models.ManyToManyField(Quiz,
                                  verbose_name=_("Quiz"),
                                  blank=True)

    category = models.ForeignKey(Category,
                                 verbose_name=_("Category"),
                                 blank=True,
                                 null=True, on_delete=models.CASCADE)

    figure = models.ImageField(upload_to='uploads/%Y/%m/%d',
                               blank=True,
                               null=True,
                               verbose_name=_("Figure"))

    content = models.CharField(max_length=1000,
                               blank=False,
                               help_text=_("Enter the question text that "
                                           "you want displayed"),
                               verbose_name=_('Question'))

    explanation = models.TextField(max_length=2000,
                                   blank=True,
                                   help_text=_("Explanation to be shown "
                                               "after the question has "
                                               "been answered."),
                                   verbose_name=_('Explanation'))

    answer_order = models.CharField(
        max_length=30, null=True, blank=True,
        choices=ANSWER_ORDER_OPTIONS,
        help_text="The order in which multichoice \
                    answer options are displayed \
                    to the user",
        verbose_name="Answer Order")

    content = models.CharField(max_length=1000,
                               blank=False,
                               help_text="Enter the answer text that \
                                            you want displayed",
                               verbose_name="Content")

    correct = models.BooleanField(blank=False,
                                  default=False,
                                  help_text="Is this a correct answer?",
                                  verbose_name="Correct")
    
    #answers = models.BooleanField(max_length=40, null=False, blank = False, help_text="Answer Choices", verbose_name="Choise")

    def check_if_correct(self, guess):
        answer = Answer.objects.get(id=guess)

        if answer.correct is True:
            return True
        else:
            return False

    def order_answers(self, queryset):
        if self.answer_order == 'content':
            return queryset.order_by('content')
        # if self.answer_order == 'random':
        #     return queryset.order_by('Random')
        if self.answer_order == 'none':
            return queryset.order_by('None')

    def get_answers(self):
        return self.order_answers(Answer.objects.filter(question=self))

    def get_answers_list(self):
        return [(answer.id, answer.content) for answer in self.order_answers(Answer.objects.filter(question=self))]

    def answer_choice_to_string(self, guess):
        return Answer.objects.get(id=guess).content

    class Meta:
        verbose_name = "Multiple Choice Question"
        verbose_name_plural = "Multiple Choice Questions"
    
    

    objects = InheritanceManager()
Ejemplo n.º 22
0
class TethysJob(models.Model):
    """
    Base class for all job types. This is intended to be an abstract class that is not directly instantiated.
    """
    class Meta:
        verbose_name = 'Job'

    objects = InheritanceManager()

    STATUSES = (
        ('PEN', 'Pending'),
        ('SUB', 'Submitted'),
        ('RUN', 'Running'),
        ('COM', 'Complete'),
        ('ERR', 'Error'),
        ('ABT', 'Aborted'),
        ('VAR', 'Various'),
        ('VCP', 'Various-Complete'),
        ('RES', 'Results-Ready'),
    )

    STATUS_DICT = {k: v for v, k in STATUSES}
    VALID_STATUSES = [v for v, _ in STATUSES]

    name = models.CharField(max_length=1024)
    description = models.CharField(max_length=2048, blank=True, default='')
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    label = models.CharField(max_length=1024)
    creation_time = models.DateTimeField(auto_now_add=True)
    execute_time = models.DateTimeField(blank=True, null=True)
    start_time = models.DateTimeField(blank=True, null=True)
    completion_time = models.DateTimeField(blank=True, null=True)
    workspace = models.CharField(max_length=1024, default='')
    extended_properties = JSONField(default=dict, null=True, blank=True)
    _process_results_function = models.CharField(max_length=1024, blank=True, null=True)
    _status = models.CharField(max_length=3, choices=STATUSES, default=STATUSES[0][0])

    @property
    def type(self):
        """
        Returns the name of Tethys Job type.
        """
        return self.__class__.__name__

    @property
    def update_status_interval(self):
        if not hasattr(self, '_update_status_interval'):
            self._update_status_interval = datetime.timedelta(seconds=10)
        return self._update_status_interval

    @property
    def last_status_update(self):
        if not getattr(self, '_last_status_update', None):
            self._last_status_update = self.execute_time or timezone.now() - self.update_status_interval
        return self._last_status_update

    @property
    def status(self):
        self.update_status()
        field = self._meta.get_field('_status')
        status = self._get_FIELD_display(field)
        return status

    @status.setter
    def status(self, value):
        self.update_status(status=value)

    @property
    def run_time(self):
        start_time = self.start_time or self.execute_time
        if start_time:
            end_time = self.completion_time or datetime.datetime.now(start_time.tzinfo)
            run_time = end_time - start_time
        else:
            return ''

        return run_time

    def execute(self, *args, **kwargs):
        """
        executes the job
        """
        self._execute(*args, **kwargs)
        self.execute_time = timezone.now()
        self._status = 'SUB'
        self.save()

    def update_status(self, status=None, *args, **kwargs):
        """
        Update status of job.
        """
        old_status = self._status

        # Set status from status given
        if status:
            if status not in self.VALID_STATUSES:
                log.error('Invalid status given: {}'.format(status))
                return

            self._status = status
            self.save()

        # Update status if status not given and still pending/running
        elif old_status in ['PEN', 'SUB', 'RUN', 'VAR'] and self.is_time_to_update():
            self._update_status(*args, **kwargs)
            self._last_status_update = timezone.now()

        # Post-process status after update if old status was pending/running
        if old_status in ['PEN', 'SUB', 'RUN', 'VAR']:
            if self._status == 'RUN' and (old_status == 'PEN' or old_status == 'SUB'):
                self.start_time = timezone.now()
            if self._status in ["COM", "VCP", "RES"]:
                self.process_results()
            elif self._status == 'ERR' or self._status == 'ABT':
                self.completion_time = timezone.now()

        self.save()

    def is_time_to_update(self):
        """
        Check if it is time to update again.

        Returns:
            bool: True if update_status_interval or longer has elapsed since our last update, else False.
        """
        time_since_last_update = timezone.now() - self.last_status_update
        is_time_to_update = time_since_last_update > self.update_status_interval
        return is_time_to_update

    @property
    def process_results_function(self):
        """

        Returns:
            A function handle or None if function cannot be resolved.
        """
        if self._process_results_function:
            function_extractor = TethysFunctionExtractor(self._process_results_function, None)
            if function_extractor.valid:
                return function_extractor.function

    @process_results_function.setter
    def process_results_function(self, function):
        if isinstance(function, str):
            self._process_results_function = function
            return
        module_path = inspect.getmodule(function).__name__.split('.')
        module_path.append(function.__name__)
        self._process_results_function = '.'.join(module_path)

    def process_results(self, *args, **kwargs):
        """
        Process the results.
        """
        log.debug('Started processing results for job: {}'.format(self))
        self._process_results(*args, **kwargs)
        self.completion_time = timezone.now()
        self._status = 'COM'
        self.save()
        log.debug('Finished processing results for job: {}'.format(self))

    @abstractmethod
    def _execute(self, *args, **kwargs):
        pass

    @abstractmethod
    def _update_status(self, *args, **kwargs):
        pass

    @abstractmethod
    def _process_results(self, *args, **kwargs):
        pass

    @abstractmethod
    def stop(self):
        """
        Stops job from executing
        """
        raise NotImplementedError()

    @abstractmethod
    def pause(self):
        """
        Pauses job during execution
        """
        raise NotImplementedError()

    @abstractmethod
    def resume(self):
        """
        Resumes a job that has been paused
        """
        raise NotImplementedError()
Ejemplo n.º 23
0
class Unit(models.Model):
    sim = models.CharField(max_length=64, null=True, blank=True)
    objects = InheritanceManager()
class PaymentMethod(models.Model):
    class PaymentProcessors:
        @classmethod
        def as_choices(cls):
            for name in settings.PAYMENT_PROCESSORS.keys():
                yield (name, name)

        @classmethod
        def as_list(cls):
            return [name for name in settings.PAYMENT_PROCESSORS.keys()]

    payment_processor = models.CharField(
        choices=PaymentProcessors.as_choices(),
        blank=False,
        null=False,
        max_length=256)
    customer = models.ForeignKey(Customer)
    added_at = models.DateTimeField(default=timezone.now)
    data = JSONField(blank=True, null=True, default={})

    verified = models.BooleanField(default=False)
    canceled = models.BooleanField(default=False)

    valid_until = models.DateTimeField(null=True, blank=True)
    display_info = models.CharField(max_length=256, null=True, blank=True)

    objects = InheritanceManager()

    class Meta:
        ordering = ['-id']

    @property
    def final_fields(self):
        return ['payment_processor', 'customer', 'added_at']

    @property
    def irreversible_fields(self):
        return ['verified', 'canceled']

    def __init__(self, *args, **kwargs):
        super(PaymentMethod, self).__init__(*args, **kwargs)

        if self.id:
            try:
                payment_method_class = self.get_payment_processor(
                ).payment_method_class

                if payment_method_class:
                    self.__class__ = payment_method_class
            except AttributeError:
                pass

    @property
    def transactions(self):
        return self.transaction_set.all()

    def get_payment_processor(self):
        return payment_processors.get_instance(self.payment_processor)

    def delete(self, using=None):
        if not self.state == self.States.Uninitialized:
            self.remove()

        super(PaymentMethod, self).delete(using=using)

    def encrypt_data(self, data):
        key = settings.PAYMENT_METHOD_SECRET
        return Fernet(key).encrypt(bytes(data))

    def decrypt_data(self, crypted_data):
        key = settings.PAYMENT_METHOD_SECRET

        try:
            return str(Fernet(key).decrypt(bytes(crypted_data)))
        except InvalidToken:
            return None

    def cancel(self):
        if self.canceled:
            raise ValidationError(
                "You can't cancel a canceled payment method.")

        cancelable_states = [
            Transaction.States.Initial, Transaction.States.Pending
        ]

        transactions = self.transactions.filter(state__in=cancelable_states)

        errors = []
        for transaction in transactions:
            if transaction.state == Transaction.States.Initial:
                try:
                    transaction.cancel()
                except TransitionNotAllowed:
                    errors.append("Transaction {} couldn't be canceled".format(
                        transaction.uuid))

            if transaction.state == Transaction.States.Pending:
                payment_processor = self.get_payment_processor()
                if (hasattr(payment_processor, 'void_transaction') and
                        not payment_processor.void_transaction(transaction)):
                    errors.append("Transaction {} couldn't be voided".format(
                        transaction.uuid))

            transaction.save()

        if errors:
            return errors

        self.canceled = True
        self.save()

        return None

    def clean_with_previous_instance(self, previous_instance):
        if not previous_instance:
            return

        for field in self.final_fields:
            old_value = getattr(previous_instance, field, None)
            current_value = getattr(self, field, None)

            if old_value != current_value:
                raise ValidationError("Field '%s' may not be changed." % field)

        for field in self.irreversible_fields:
            old_value = getattr(previous_instance, field, None)
            current_value = getattr(self, field, None)

            if old_value and old_value != current_value:
                raise ValidationError(
                    "Field '%s' may not be changed anymore." % field)

    def full_clean(self, *args, **kwargs):
        previous_instance = kwargs.pop('previous_instance', None)

        super(PaymentMethod, self).full_clean(*args, **kwargs)
        self.clean_with_previous_instance(previous_instance)

        # this assumes that nobody calls clean and then modifies this object
        # without calling clean again
        setattr(self, '.cleaned', True)

    @property
    def allowed_currencies(self):
        return self.get_payment_processor().allowed_currencies

    @property
    def public_data(self):
        return {}

    def __unicode__(self):
        return u'{} - {}'.format(self.customer,
                                 self.get_payment_processor_display())
Ejemplo n.º 25
0
class Character(Model):
    objects = InheritanceManager()

    character = OneToOneField(ObjectDB, on_delete=CASCADE, primary_key=True)

    strength = IntegerField(default=1)
    dexterity = IntegerField(default=1)
    stamina = IntegerField(default=1)
    intelligence = IntegerField(default=1)
    wits = IntegerField(default=1)
    resolve = IntegerField(default=1)
    presence = IntegerField(default=1)
    manipulation = IntegerField(default=1)
    composure = IntegerField(default=1)

    academics = IntegerField(default=0)
    computer = IntegerField(default=0)
    crafts = IntegerField(default=0)
    investigation = IntegerField(default=0)
    medicine = IntegerField(default=0)
    occult = IntegerField(default=0)
    politics = IntegerField(default=0)
    science = IntegerField(default=0)
    athletics = IntegerField(default=0)
    brawl = IntegerField(default=0)
    drive = IntegerField(default=0)
    firearms = IntegerField(default=0)
    larceny = IntegerField(default=0)
    stealth = IntegerField(default=0)
    survival = IntegerField(default=0)
    weaponry = IntegerField(default=0)
    animal_ken = IntegerField(default=0)
    empathy = IntegerField(default=0)
    expression = IntegerField(default=0)
    intimidation = IntegerField(default=0)
    persuasion = IntegerField(default=0)
    socialize = IntegerField(default=0)
    streetwise = IntegerField(default=0)
    subterfuge = IntegerField(default=0)

    size = IntegerField(default=5)

    temporary_willpower = IntegerField(default=0)
    permanent_willpower = IntegerField(default=0)

    @property
    def maximum_willpower(self):
        return self.get('wits') + self.get('resolve') - self.permanent_willpower

    @property
    def current_willpower(self):
        return self.maximum_willpower - self.temporary_willpower

    bashing = IntegerField(default=0)
    lethal = IntegerField(default=0)
    aggravated = IntegerField(default=0)

    @property
    def maximum_health(self):
        return self.get('size') + self.get('stamina') + self.get_bonuses('health')

    @property
    def undamaged(self):
        return max(self.maximum_health - self.bashing - self.lethal - self.aggravated, 0)

    @property
    def speed(self):
        return 5 + self.get('strength') + self.get('dexterity')

    @property
    def initiative(self):
        return self.get('dexterity') + self.get('composure')

    @property
    def defense(self):
        return min(self.get('dexterity'), self.get('wits')) + self.get('athletics')

    def get(self, stat):
        current = getattr(self, stat)
        if isinstance(current, int):
            return current + self.get_bonuses(stat)
        else:
            return current

    def get_bonuses(self, stat):
        return 0

    def display_stat(self, name, width=20):
        display_name = name.replace('_', ' ')
        display_name = display_name.title()
        display_name = display_name.ljust(width - 2)
        value = self.get(name)
        return f'{display_name} {value}'

    @property
    def display_attributes(self):
        return f"""
        {self.display_stat('intelligence')} {self.display_stat('strength')} {self.display_stat('presence')}
        {self.display_stat('wits')} {self.display_stat('dexterity')} {self.display_stat('manipulation')}
        {self.display_stat('resolve')} {self.display_stat('stamina')} {self.display_stat('composure')}
        """.strip()

    @property
    def display_skills(self):
        return f"""
        {self.display_stat('academics')} {self.display_stat('athletics')} {self.display_stat('animal_ken')}
        {self.display_stat('computer')} {self.display_stat('brawl')} {self.display_stat('empathy')}
        {self.display_stat('crafts')} {self.display_stat('drive')} {self.display_stat('expression')}
        {self.display_stat('investigation')} {self.display_stat('firearms')} {self.display_stat('intimidation')}
        {self.display_stat('medicine')} {self.display_stat('larceny')} {self.display_stat('persuasion')}
        {self.display_stat('occult')} {self.display_stat('stealth')} {self.display_stat('socialize')}
        {self.display_stat('politics')} {self.display_stat('survival')} {self.display_stat('streetwise')}
        {self.display_stat('science')} {self.display_stat('weaponry')} {self.display_stat('subterfuge')}
        """.strip()

    @property
    def mental_attributes(self):
        return sum([
            self.intelligence,
            self.wits,
            self.resolve
        ])

    @property
    def physical_attributes(self):
        return sum([
            self.strength,
            self.dexterity,
            self.stamina
        ])

    @property
    def social_attributes(self):
        return sum([
            self.presence,
            self.manipulation,
            self.composure
        ])

    @property
    def mental_skills(self):
        return sum([
            self.academics,
            self.computer,
            self.crafts,
            self.investigation,
            self.medicine,
            self.occult,
            self.politics,
            self.science
        ])

    @property
    def physical_skills(self):
        return sum([
            self.athletics,
            self.brawl,
            self.drive,
            self.firearms,
            self.larceny,
            self.stealth,
            self.survival,
            self.weaponry
        ])

    @property
    def social_skills(self):
        return sum([
            self.animal_ken,
            self.empathy,
            self.expression,
            self.intimidation,
            self.persuasion,
            self.socialize,
            self.streetwise,
            self.subterfuge
        ])
Ejemplo n.º 26
0
class Record(models.Model):
    visitor = models.ForeignKey(settings.AUTH_USER_MODEL,
                                on_delete=models.PROTECT)
    visited_at = models.DateTimeField(auto_now_add=True)
    objects = InheritanceManager()
Ejemplo n.º 27
0
class OrderItem(models.Model):
    """
    This is the basic interface for order items.
    Order items are line items that fill up the shopping carts and orders.

    Each implementation of OrderItem should provide its own purchased_callback as
    a method.
    """
    objects = InheritanceManager()
    order = models.ForeignKey(Order, db_index=True)
    # this is denormalized, but convenient for SQL queries for reports, etc. user should always be = order.user
    user = models.ForeignKey(User, db_index=True)
    # this is denormalized, but convenient for SQL queries for reports, etc. status should always be = order.status
    status = models.CharField(max_length=32,
                              default='cart',
                              choices=ORDER_STATUSES)
    qty = models.IntegerField(default=1)
    unit_cost = models.DecimalField(default=0.0,
                                    decimal_places=2,
                                    max_digits=30)
    line_desc = models.CharField(default="Misc. Item", max_length=1024)
    currency = models.CharField(default="usd",
                                max_length=8)  # lower case ISO currency codes
    fulfilled_time = models.DateTimeField(null=True)

    @property
    def line_cost(self):
        """ Return the total cost of this OrderItem """
        return self.qty * self.unit_cost

    @classmethod
    def add_to_order(cls, order, *args, **kwargs):
        """
        A suggested convenience function for subclasses.

        NOTE: This does not add anything to the cart. That is left up to the
        subclasses to implement for themselves
        """
        # this is a validation step to verify that the currency of the item we
        # are adding is the same as the currency of the order we are adding it
        # to
        currency = kwargs.get('currency', 'usd')
        if order.currency != currency and order.orderitem_set.exists():
            raise InvalidCartItem(
                _("Trying to add a different currency into the cart"))

    @transaction.commit_on_success
    def purchase_item(self):
        """
        This is basically a wrapper around purchased_callback that handles
        modifying the OrderItem itself
        """
        self.purchased_callback()
        self.status = 'purchased'
        self.fulfilled_time = datetime.now(pytz.utc)
        self.save()

    def purchased_callback(self):
        """
        This is called on each inventory item in the shopping cart when the
        purchase goes through.
        """
        raise NotImplementedError

    @property
    def single_item_receipt_template(self):
        """
        The template that should be used when there's only one item in the order
        """
        return 'shoppingcart/receipt.html'

    @property
    def single_item_receipt_context(self):
        """
        Extra variables needed to render the template specified in
        `single_item_receipt_template`
        """
        return {}

    @property
    def additional_instruction_text(self):
        """
        Individual instructions for this order item.

        Currently, only used for e-mails.
        """
        return ''
Ejemplo n.º 28
0
class Widget(models.Model):
    """ Defines a UI widget and the source datatables
    """
    tables = models.ManyToManyField(Table)
    section = models.ForeignKey(Section)
    title = models.CharField(max_length=100)
    row = models.IntegerField()
    col = models.IntegerField()
    width = models.IntegerField(default=1)
    height = models.IntegerField(default=300)
    rows = models.IntegerField(default=-1)
    options = PickledObjectField()

    module = models.CharField(max_length=100)
    uiwidget = models.CharField(max_length=100)
    uioptions = PickledObjectField()

    # not globally unique, but should be sufficiently unique within a report
    slug = models.SlugField(max_length=100)

    objects = InheritanceManager()

    def __repr__(self):
        return '<Widget %s (%s)>' % (self.title, self.id)

    def __unicode__(self):
        return '<Widget %s (%s)>' % (self.title, self.id)

    def save(self, *args, **kwargs):
        self.slug = '%s-%d-%d' % (slugify(self.title), self.row, self.col)
        super(Widget, self).save(*args, **kwargs)

    def get_definition(self, criteria):
        """Get dict of widget attributes for sending via JSON."""
        report = self.section.report

        widget_def = {
            "widgettype":
            self.widgettype().split("."),
            "posturl":
            reverse('widget-job-list',
                    args=(report.namespace, report.slug, self.slug)),
            "updateurl":
            reverse('widget-criteria',
                    args=(report.namespace, report.slug, self.slug)),
            "options":
            self.uioptions,
            "widgetid":
            self.id,
            "widgetslug":
            self.slug,
            "row":
            self.row,
            "width":
            self.width,
            "height":
            self.height,
            "criteria":
            criteria,
        }

        return widget_def

    def widgettype(self):
        return '%s.%s' % (self.module.split('.')[-1], self.uiwidget)

    def table(self, i=0):
        return self.tables.all()[i]

    def compute_row_col(self):
        rowmax = self.section.report.widgets().aggregate(Max('row'))
        row = rowmax['row__max']
        if row is None:
            row = 1
            col = 1
        else:
            widthsum = (self.section.report.widgets().filter(
                row=row).aggregate(Sum('width')))
            width = widthsum['width__sum']
            if width + self.width > 12:
                row += 1
                col = 1
            else:
                col = width + 1
        self.row = row
        self.col = col

    def collect_fields(self):
        # Gather up all fields
        fields = SortedDict()

        # All fields attached to the section's report
        for f in self.section.report.fields.all().order_by('id'):
            fields[f.keyword] = f

        # All fields attached to the section
        for f in self.section.fields.all().order_by('id'):
            if f.keyword not in fields:
                fields[f.keyword] = f

        # All fields attached to any Widget's Tables
        for w in self.section.widget_set.all().order_by('id'):
            for t in w.tables.all():
                for f in t.fields.all().order_by('id'):
                    if f.keyword not in fields:
                        fields[f.keyword] = f

        return fields
Ejemplo n.º 29
0
class BasicArticle(models.Model):
    allowed = models.BooleanField(default=True)
    author = models.ForeignKey(User, on_delete=models.PROTECT, related_name='articles', null=True, blank=True)
    title = models.CharField(max_length=256, default='')
    text = models.TextField()
    pubdate = models.DateTimeField('date published', default=datetime.now)
    pluses = models.ManyToManyField(User, blank=True, related_name='plused_articles')
    minuses = models.ManyToManyField(User, blank=True, related_name='minused_articles')
    views = models.ManyToManyField(User, blank=True, related_name='viewed_articles')
    allow_comments = models.BooleanField(default=True, null=True)
    comments = models.OneToOneField(CommentsList, on_delete=models.CASCADE, null=True, blank=True,
                                    related_name="article")
    files = models.OneToOneField(ArticleFilesList, on_delete=models.CASCADE, null=True, blank=True,
                                 related_name="article")

    rating = models.IntegerField(default=0)

    objects = InheritanceManager()

    def class_name(self):
        return self.__class__.__name__

    def has_rights(self, user):
        return False

    def can_react(self, user):
        if self.__class__.__name__ != 'CommunityArticle':
            return user.is_authenticated and self.can_see_article(user) and self.author != user
        return user.is_authenticated and self.can_see_article(user)

    def update_rating(self):
        article = self.get_child()
        article.rating = article.pluses.count() - article.minuses.count()
        article.save()

    def increase_rating(self):
        article = self.get_child()
        self.rating += 1
        if article.__class__.__name__ == 'PersonalArticle':
            article.author.profile.rating += 1
            article.author.profile.save()
        elif article.__class__.__name__ == 'PersonalInCommunityArticle':
            article.author.profile.rating += 1
            article.group.rating += 1
            article.author.profile.save()
            article.group.save()
        elif article.__class__.__name__ == 'CommunityArticle':
            article.group.rating += 1
            article.group.save()
        self.save()

    def decrease_rating(self):
        article = self.get_child()
        self.rating -= 1
        if article.__class__.__name__ == 'PersonalArticle':
            article.author.profile.rating -= 1
            article.author.profile.save()
        elif article.__class__.__name__ == 'PersonalInCommunityArticle':
            article.author.profile.rating -= 1
            article.group.rating -= 1
            article.author.profile.save()
            article.group.save()
        elif article.__class__.__name__ == 'CommunityArticle':
            article.group.rating -= 1
            article.group.save()
        self.save()

    def can_see_article(self, user=None):
        return False

    def can_edit_article(self, user):
        if self.__class__.__name__ != 'PersonalArticle':
            return self.group.has_power(user) or (
                not self.allowed and self.__class__.__name__ == 'PersonalInCommunityArticle' and self.author == user)
        return user == self.author

    def can_comment_article(self, user):
        return self.allow_comments and self.can_see_article(user)

    def get_child(self):
        return BasicArticle.objects.get_subclass(id=self.id)

    def get_child_type(self):
        return BasicArticle.objects.get_subclass(id=self.id).class_name()

    def plus(self, user):
        if user not in self.pluses.all():
            self.pluses.add(user)
            self.increase_rating()
        if user in self.minuses.all():
            self.minuses.remove(user)
            self.increase_rating()
        self.save()

    def minus(self, user):
        if user in self.pluses.all():
            self.pluses.remove(user)
            self.decrease_rating()
        if user not in self.minuses.all():
            self.minuses.add(user)
            self.decrease_rating()
        self.save()

    def remove_plus(self, user):
        if user in self.pluses.all():
            self.pluses.remove(user)
            self.decrease_rating()
            self.save()

    def remove_minus(self, user):
        if user in self.minuses.all():
            self.minuses.remove(user)
            self.increase_rating()
            self.save()

    def get_rating(self):
        return self.pluses.count() - self.minuses.count()

    def __str__(self):
        if self.title:
            return self.title
        return self.text
Ejemplo n.º 30
0
class ProductVariant(models.Model, Item):
    sku = models.CharField(pgettext_lazy('Variant field', 'SKU'),
                           max_length=32,
                           unique=True)
    name = models.CharField(pgettext_lazy('Variant field', 'variant name'),
                            max_length=100,
                            blank=True)
    price_override = PriceField(pgettext_lazy('Variant field',
                                              'price override'),
                                currency=settings.DEFAULT_CURRENCY,
                                max_digits=12,
                                decimal_places=2,
                                blank=True,
                                null=True)
    weight_override = WeightField(pgettext_lazy('Variant field',
                                                'weight override'),
                                  unit=settings.DEFAULT_WEIGHT,
                                  max_digits=6,
                                  decimal_places=2,
                                  blank=True,
                                  null=True)
    product = models.ForeignKey(Product, related_name='variants')
    attributes = JSONField(pgettext_lazy('Variant field', 'attributes'),
                           default={})
    images = models.ManyToManyField('ProductImage', through='VariantImage')
    objects = InheritanceManager()

    class Meta:
        app_label = 'product'

    def __str__(self):
        return self.name or self.sku

    def get_weight(self):
        return self.weight_override or self.product.weight

    def check_quantity(self, quantity):
        available_quantity = self.get_stock_quantity()
        if quantity > available_quantity:
            raise InsufficientStock(self)

    def get_stock_quantity(self):
        if not len(self.stock.all()):
            return 0
        return max([stock.quantity_available for stock in self.stock.all()])

    def get_price_per_item(self, discounts=None, **kwargs):
        price = self.price_override or self.product.price
        if discounts:
            discounts = list(get_variant_discounts(self, discounts, **kwargs))
            if discounts:
                price = min(price | discount for discount in discounts)
        return price

    def get_absolute_url(self):
        slug = self.product.get_slug()
        product_id = self.product.id
        return reverse('product:details',
                       kwargs={
                           'slug': slug,
                           'product_id': product_id
                       })

    def as_data(self):
        return {
            'product_name': str(self),
            'product_id': self.product.pk,
            'variant_id': self.pk,
            'unit_price': str(self.get_price_per_item().gross)
        }

    def is_shipping_required(self):
        return True

    def is_in_stock(self):
        return any(
            [stock.quantity_available > 0 for stock in self.stock.all()])

    def get_attribute(self, pk):
        return self.attributes.get(str(pk))

    def display_variant(self, attributes=None):
        if attributes is None:
            attributes = self.product.attributes.all()
        values = get_attributes_display_map(self, attributes).values()
        if values:
            return ', '.join([smart_text(value) for value in values])
        else:
            return smart_text(self)

    def display_product(self, attributes=None):
        return '%s (%s)' % (smart_text(
            self.product), self.display_variant(attributes=attributes))

    def select_stockrecord(self, quantity=1):
        # By default selects stock with lowest cost price
        stock = filter(lambda stock: stock.quantity_available >= quantity,
                       self.stock.all())
        stock = sorted(stock, key=lambda stock: stock.cost_price, reverse=True)
        if stock:
            return stock[0]

    def get_cost_price(self):
        stock = self.select_stockrecord()
        if stock:
            return stock.cost_price