Esempio n. 1
0
    def get_list_queryset(self, queryset):
        lookup_params = dict([
            (smart_str(k)[len(FILTER_PREFIX):], v)
            for k, v in self.admin_view.params.items()
            if smart_str(k).startswith(FILTER_PREFIX) and v != ''
        ])
        for p_key, p_val in iteritems(lookup_params):
            if p_val == "False":
                lookup_params[p_key] = False
        use_distinct = False

        # for clean filters
        self.admin_view.has_query_param = bool(lookup_params)
        self.admin_view.clean_query_url = self.admin_view.get_query_string(
            remove=[
                k for k in self.request.GET.keys()
                if k.startswith(FILTER_PREFIX)
            ])

        # Normalize the types of keys
        if not self.free_query_filter:
            for key, value in lookup_params.items():
                if not self.lookup_allowed(key, value):
                    raise SuspiciousOperation("Filtering by %s not allowed" %
                                              key)

        self.filter_specs = []
        if self.list_filter:
            for list_filter in self.list_filter:
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(self.request, lookup_params, self.model,
                                       self)
                else:
                    field_path = None
                    field_parts = []
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, filter_manager.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field_parts = get_fields_from_path(
                            self.model, field_path)
                        field = field_parts[-1]
                    spec = field_list_filter_class(field,
                                                   self.request,
                                                   lookup_params,
                                                   self.model,
                                                   self.admin_view,
                                                   field_path=field_path)

                    if len(field_parts) > 1:
                        # Add related model name to title
                        spec.title = "%s %s" % (field_parts[-2].name,
                                                spec.title)

                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or lookup_needs_distinct(
                        self.opts, field_path))
                if spec and spec.has_output():
                    try:
                        new_qs = spec.do_filte(queryset)
                    except ValidationError as e:
                        new_qs = None
                        self.admin_view.message_user(
                            _("<b>Filtering error:</b> %s") % e.messages[0],
                            'error')
                    if new_qs is not None:
                        queryset = new_qs

                    self.filter_specs.append(spec)

        self.has_filters = bool(self.filter_specs)
        self.admin_view.filter_specs = self.filter_specs
        obj = filter(lambda f: f.is_used, self.filter_specs)
        if six.PY3:
            obj = list(obj)
        self.admin_view.used_filter_num = len(obj)

        try:
            for key, value in lookup_params.items():
                use_distinct = (use_distinct
                                or lookup_needs_distinct(self.opts, key))
        except FieldDoesNotExist as e:
            raise IncorrectLookupParameters(e)

        try:
            # fix a bug by david: In demo, quick filter by IDC Name() cannot be used.
            if isinstance(queryset, models.query.QuerySet) and lookup_params:
                new_lookup_parames = dict()
                for k, v in lookup_params.items():
                    list_v = v.split(',')
                    if len(list_v) > 0:
                        new_lookup_parames.update({k: list_v})
                    else:
                        new_lookup_parames.update({k: v})
                queryset = queryset.filter(**new_lookup_parames)
        except (SuspiciousOperation, ImproperlyConfigured):
            raise
        except Exception as e:
            raise IncorrectLookupParameters(e)
        else:
            if not isinstance(queryset, models.query.QuerySet):
                pass

        query = self.request.GET.get(SEARCH_VAR, '')

        # Apply keyword searches.
        def construct_search(field_name):
            if field_name.startswith('^'):
                return "%s__istartswith" % field_name[1:]
            elif field_name.startswith('='):
                return "%s__iexact" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__icontains" % field_name

        if self.search_fields and query:
            orm_lookups = [
                construct_search(str(search_field))
                for search_field in self.search_fields
            ]
            for bit in query.split():
                or_queries = [
                    models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups
                ]
                queryset = queryset.filter(reduce(operator.or_, or_queries))
            if not use_distinct:
                for search_spec in orm_lookups:
                    if lookup_needs_distinct(self.opts, search_spec):
                        use_distinct = True
                        break
            self.admin_view.search_query = query

        if use_distinct:
            return queryset.distinct()
        else:
            return queryset
Esempio n. 2
0
 def search(self, query):
     return self.get_queryset().filter(
         models.Q(name__icontains=query) | \
         models.Q(description__icontains=query)
     )
Esempio n. 3
0
 def get_context_data(self, **kwargs):
     context = super(ReportMargins, self).get_context_data(**kwargs)
     if self.form.is_valid():
         venture = Venture.objects.get(
             id=self.form.cleaned_data['margin_venture'])
         query = HistoryCost.objects.filter(
             db.Q(venture=venture) | db.Q(venture__parent=venture)
             | db.Q(venture__parent__parent=venture)
             | db.Q(venture__parent__parent__parent=venture)
             | db.Q(venture__parent__parent__parent__parent=venture))
         total_cost = 0
         total_sim = 0
         total_count = 0
         for mk in self.margin_kinds:
             q = query.filter(
                 db.Q(device__margin_kind=mk) | db.Q(
                     db.Q(device__margin_kind=None) & db.Q(
                         db.Q(device__venture__margin_kind=mk)
                         | db.Q(device__venture__margin_kind=None,
                                device__venture__parent__margin_kind=mk)
                         | db.
                         Q(device__venture__margin_kind=None,
                           device__venture__parent__margin_kind=None,
                           device__venture__parent__parent__margin_kind=mk)
                         | db.
                         Q(device__venture__margin_kind=None,
                           device__venture__parent__margin_kind=None,
                           device__venture__parent__parent__margin_kind=None,
                           device__venture__parent__parent__parent__margin_kind
                           =mk))))
             mk.total, mk.count, mk.count_now = total_cost_count(
                 q,
                 self.form.cleaned_data['start'],
                 self.form.cleaned_data['end'],
             )
             mk.sim_margin = self.form.get('m_%d' % mk.id, 0) or 0
             mk.sim_cost = ((mk.total or 0) / (1 + mk.margin / 100) *
                            (1 + mk.sim_margin / 100))
             total_sim += mk.sim_cost
             total_cost += mk.total or 0
             total_count += mk.count or 0
         context.update({
             'venture': venture,
             'total_cost': total_cost,
             'total_sim': total_sim,
             'total_count': total_count,
         })
     context.update({
         'form':
         self.form,
         'margin_kinds':
         self.margin_kinds,
         'zip_margin_kinds_form':
         zip([f for f in self.form if not f.label], self.margin_kinds),
     })
     return context
Esempio n. 4
0
    def update_liabilites(self):
        src_account = SpecialAccounts.fees
        dst_account = SpecialAccounts.fees_receivable

        config = Configuration.get_solo()

        # Step 1: Identify all dates and amounts that should be due at those dates
        #  (in python, store as a list; hits database once to get list of memberships)
        # Step 2: Find all due amounts within the data ranges, ignore reversed liabilities
        #  (hits database)
        # Step 3: Compare due date and amounts with list from step 1
        #  (in Python)
        # Step 4: Cancel all liabilities that didn't match in step 3
        #  (hits database, once per mismatch)
        # Step 5: Add all missing liabilities
        #  (hits database, once per new due)
        # Step 6: Find and cancel all liabilities outside of membership dates, replaces remove_future_liabilites_on_leave()
        #  (hits database, once for search, once per stray liability)

        dues = set()
        membership_ranges = []
        _now = now()
        _from = config.accounting_start

        # Step 1
        for membership in self.memberships.all():
            if not membership.amount:
                continue
            membership_range, membership_dues = membership.get_dues(
                _now=_now, _from=_from
            )
            membership_ranges.append(membership_range)
            dues |= membership_dues

        # Step 2
        dues_qs = Booking.objects.filter(
            member=self,
            credit_account=src_account,
            transaction__reversed_by__isnull=True,
        )
        if membership_ranges:
            date_range_q = reduce(
                lambda a, b: a | b,
                [
                    models.Q(transaction__value_datetime__gte=start)
                    & models.Q(transaction__value_datetime__lte=end)
                    for start, end in membership_ranges
                ],
            )
            dues_qs = dues_qs.filter(date_range_q)
        dues_in_db = {  # Must be a dictionary instead of set, to retrieve b later on
            (b.transaction.value_datetime.date(), b.amount): b for b in dues_qs.all()
        }

        # Step 3
        dues_in_db_as_set = set(dues_in_db.keys())
        wrong_dues_in_db = dues_in_db_as_set - dues
        missing_dues = dues - dues_in_db_as_set

        # Step 4
        for wrong_due in sorted(wrong_dues_in_db):
            booking = dues_in_db[wrong_due]
            booking.transaction.reverse(
                memo=_("Due amount canceled because of change in membership amount"),
                user_or_context="internal: update_liabilites, membership amount changed",
            )

        # Step 5:
        for (date, amount) in sorted(missing_dues):
            t = Transaction.objects.create(
                value_datetime=date,
                booking_datetime=_now,
                memo=_("Membership due"),
                user_or_context="internal: update_liabilites, add missing liabilities",
            )
            t.credit(
                account=src_account,
                amount=amount,
                member=self,
                user_or_context="internal: update_liabilites, add missing liabilities",
            )
            t.debit(
                account=dst_account,
                amount=amount,
                member=self,
                user_or_context="internal: update_liabilites, add missing liabilities",
            )
            t.save()

        # Step 6:
        stray_liabilities_qs = Booking.objects.filter(
            member=self,
            credit_account=src_account,
            transaction__reversed_by__isnull=True,
        )
        if membership_ranges:
            stray_liabilities_qs = stray_liabilities_qs.exclude(date_range_q)
        stray_liabilities_qs = stray_liabilities_qs.prefetch_related("transaction")
        for stray_liability in stray_liabilities_qs.all():
            stray_liability.transaction.reverse(
                memo=_("Due amount outside of membership canceled"),
                user_or_context="internal: update_liabilites, reverse stray liabilities",
            )
Esempio n. 5
0
 class Meta:
     required_db_features = {'supports_table_check_constraints'}
     constraints = [
         models.CheckConstraint(check=models.Q(age__gte=18),
                                name='is_adult')
     ]
Esempio n. 6
0
 def search(self, query):
     return self.get_queryset().filter(
         models.Q(internal_reference__icontains=query)
         | models.Q(name__icontains=query)
         | models.Q(description__icontains=query))
Esempio n. 7
0
 def search(self, query):
     return self.get_queryset().filter(models.Q(name__icontains=query) | \
      models.Q(created_at__icontains=query))
Esempio n. 8
0
def object_has_region(user):
    """
    Check if object's region is one of user regions.
    """
    return models.Q(region__in=user.regions_ids)
Esempio n. 9
0
class CytoScape(models.Model):
    ALLOWED_INITIAL_CONTENT_TYPES = models.Q(app_label='quest_manager', model='quest') | \
                                    models.Q(app_label='badges', model='badge') | \
                                    models.Q(app_label='courses', model='rank')

    name = models.CharField(max_length=250)
    style_set = models.ForeignKey(CytoStyleSet,
                                  null=True,
                                  on_delete=models.SET_NULL)

    # initial_object = models.OneToOneField(Quest)

    # The initial object
    initial_content_type = models.ForeignKey(
        ContentType,
        on_delete=models.CASCADE,
        limit_choices_to=ALLOWED_INITIAL_CONTENT_TYPES)
    initial_object_id = models.PositiveIntegerField(
        help_text="The id of the object for this content type. "
        "You may need to look this up.  E.g. If the initial type "
        "is a quest, then the quest's id goes here.")
    initial_content_object = GenericForeignKey('initial_content_type',
                                               'initial_object_id')

    parent_scape = models.ForeignKey(
        'self',
        blank=True,
        null=True,
        help_text=
        "The map/scape preceding this one, so it can be linked back to",
        on_delete=models.CASCADE)
    is_the_primary_scape = models.BooleanField(
        default=False,
        help_text="There can only be one primary map/scape. Making this True "
        "will change all other map/scapes will be set to False.")
    last_regeneration = models.DateTimeField(default=timezone.now)
    container_element_id = models.CharField(
        max_length=50,
        default="cy",
        help_text=
        "id of the html element where the graph's canvas will be placed")
    autobreak = models.BooleanField(
        default=True,
        help_text=
        "Stop the map when reaching a quest with a ~ or a badge with a *."
        "If this is unchecked, the map is gonna be CRAZY!")

    class Meta:
        unique_together = (('initial_content_type', 'initial_object_id'), )
        verbose_name = "Quest Map"

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        # if this is the first scape, make it primary
        if CytoScape.objects.all().count() == 0:
            self.is_the_primary_scape = True
        # if setting this to primary, turn other primary to False
        elif self.is_the_primary_scape:
            try:
                current_primary_scape = CytoScape.objects.get(
                    is_the_primary_scape=True)
                if self != current_primary_scape:
                    current_primary_scape.is_the_chosen_one = False
                    current_primary_scape.save()
            except CytoScape.DoesNotExist:
                pass
        super(CytoScape, self).save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse('djcytoscape:quest_map', kwargs={'scape_id': self.id})

    objects = CytoScapeManager()

    def json(self):
        elements = self.cytoelement_set.all()
        print(elements)

        json_str = "cytoscape({ \n"
        json_str += "  container: document.getElementById('" + self.container_element_id + "'), \n"
        json_str += "  elements: [ \n"
        for element in elements:
            json_str += element.json()
        json_str += "  ], \n"
        json_str += self.style_set.get_layout_json()
        json_str += "  style: [ \n"
        json_str += self.style_set.get_node_styles()
        json_str += self.style_set.get_edge_styles()
        json_str += self.style_set.get_parent_styles()
        json_str += self.style_set.get_classes()
        # json_str += self.get_selector_styles_json('.Quest', self.quest_styles)
        # json_str += self.get_selector_styles_json('.Badge', self.badge_styles)
        # json_str += self.get_selector_styles_json('.campaign', self.campaign_styles)
        # json_str += self.get_selector_styles_json('.hidden', self.hidden_styles)
        # json_str += self.get_selector_styles_json('.link', self.link_styles)
        # json_str += self.get_selector_styles_json('.link_hover', self.link_hover_styles)
        for element in elements:
            if element.id_styles:
                json_str += self.get_selector_styles_json(
                    str(element.id), element.id_styles)
        json_str += "  ], \n"  # end style: [
        json_str += self.style_set.get_init_options()
        json_str += "});"

        return json_str

    @staticmethod
    def get_selector_styles_json(selector, styles):
        json_str = "    { \n"
        json_str += "      selector: '#" + selector + "', \n"
        json_str += "      style: { \n"
        json_str += styles
        json_str += "      } \n"
        json_str += "    }, \n"
        return json_str

    @staticmethod
    def generate_label(obj):
        max_len = 44  # max label length in characters
        post = ""
        pre = ""
        if type(obj) is Badge:
            pre = "Badge: "
        elif type(obj) is Rank:
            pre = "Rank: "
        title = pre + str(obj)
        # shorten the end
        if len(title) > max_len:
            title = title[:(max_len - 3)] + "..."  # + title[-int(l/2-2):]
        if hasattr(obj, 'xp'):
            post = " (" + str(obj.xp) + ")"
        # if hasattr(obj, 'max_repeats'): # stop trying to be fancy!
        #     if obj.max_repeats != 0:
        #         post += ' ⟲'

        # json.dumps to escape special characters in the object, such as single and double quote marks.
        # dumps not working...just try manually
        title = title.replace('"', '\\"')
        return title + post

    def get_last_node_in_campaign(self, parent_node, offset=0):
        """
        :param offset: offset from last node by this (i.e. 1 --> second last node)
        :param parent_node: the compound node/parent, i.e. campaign
        :return: the most recent node added to the campaign (added to the compound/parent node) by using the highest id
        """
        try:
            # latest normally used with dates, but actually works with other fields too!
            # return CytoElement.objects.all_for_campaign(self, parent_node).latest('id')
            qs = CytoElement.objects.all_for_campaign(
                self, parent_node).order_by('-id')
            return qs[offset]
        except self.DoesNotExist:
            return None

    def add_node_from_object(self, obj, initial_node=False):
        # If node node doesn't exist already, create a new one

        # check for an icon
        if hasattr(obj, 'get_icon_url'):
            img_url = obj.get_icon_url()
        else:
            img_url = "none"

        new_node, created = CytoElement.objects.get_or_create(
            scape=self,
            group=CytoElement.NODES,
            selector_id=CytoElement.generate_selector_id(obj),
            label=self.generate_label(obj),
            defaults={
                'id_styles': "'background-image': '" + img_url + "'",
                'classes': type(obj).__name__,
            })

        # if this is a transition node (to a new map), add the link to href field. And add the "link" class
        if not initial_node and self.is_transition_node(new_node):
            ct = ContentType.objects.get_for_model(obj)
            obj = ct.get_object_for_this_type(id=obj.id)

            # <content_type_id>, <object_id>, <originating_scape_id>
            new_node.href = reverse('maps:quest_map_interlink',
                                    args=[ct.id, obj.id, self.id])
            new_node.classes += " link"
            new_node.save()
        else:  # add a link to the object itself
            new_node.href = obj.get_absolute_url()
            new_node.save()

        return new_node, created

    def init_temp_campaign_list(self):
        """
        Create a new member variable `campaign_list` or clear it if it already exists
        """
        self.campaign_list = []

    def get_temp_campaign(self, campaign_id):
        for campaign in self.campaign_list:
            try:
                if campaign.node_id == campaign_id:
                    return campaign
            except ValueError:
                pass
        return None

    def add_to_campaign(self, obj, node, mother_node):
        """
        Checks if obj is in a campaign, if so, gets or creates the campaign_node (Parent/compound node)
        and adds is as the parent node.  Also registers the node and parent with the TempCampaign (for edges later)
        :param mother_node: prereq node
        :param obj:
        :param node: node of the object
        :return: campaign_node = None if obj isn't part of a campaign, otherwise = the campaign_node (i.e. parent_node)
        campaign_created = False if obj is in campaign, but the campaign was created by an earlier node
        """
        # If part of a campaign, create parent and add to "parent" node, i.e. compound node
        campaign_node = None
        campaign_created = False
        if hasattr(obj, 'campaign') and obj.campaign is not None:
            # parent_name = str(obj.campaign)
            campaign_node, campaign_created = CytoElement.objects.get_or_create(
                scape=self,
                group=CytoElement.NODES,
                label=str(obj.campaign),
                classes="campaign",
                # defaults={'attribute': value},
            )
            # Add parent
            node.data_parent = campaign_node
            node.save()

            # TempCampaign utility
            if campaign_created:
                self.campaign_list.append(TempCampaign(campaign_node.id))
            temp_campaign = self.get_temp_campaign(campaign_node.id)
            # temp_campaign.add_child(node.id)
            # TODO: Nodes might be present multiple times through different mothers?  check and combine
            temp_campaign.add_node(node.id, mother_node.id)
            # temp_campaign.add_prereq(mother_node.id)

        return campaign_node, campaign_created

    def fix_nonsequential_campaign_edges(self):
        """
        cyto dagre layout doesn't support compound/parent nodes, so for non-sequential/non-directed campaigns
        (i.e. all quests are available concurrently) we need to:
         1. add invisible edges joining the quests
         2. remove edges between common prereqs and quests
         3. remove edges between quests and common reliants
         4. add edges between common prereqs and campaign/compound/parent node
         5. add edges between campaign/compound/parent node and common reliants
         6. add invisible edge (for structure) from prereqs to first node
         7. add invisible edge (for structure) from last node to reliants
        """

        for campaign in self.campaign_list:

            common_prereq_ids = campaign.get_common_prereq_node_ids()
            if common_prereq_ids:  # then non-sequential campaign

                # 1. add invisible edges joining the quests
                for current_node in campaign.nodes:
                    next_node = campaign.get_next_node(current_node)
                    if next_node:
                        CytoElement.objects.get_or_create(
                            scape=self,
                            group=CytoElement.EDGES,
                            data_source_id=current_node.id,
                            data_target_id=next_node.id,
                            defaults={
                                'classes': 'hidden',
                            },
                        )

                first_node = campaign.get_first_node()
                for prereq_node_id in common_prereq_ids:

                    # 2. remove edges between common prereqs and quests
                    for quest_node in campaign.nodes:
                        # we already know all quests have this prereq node in common, so the edges should all exist
                        # unless quest has internal prereq...
                        if prereq_node_id in quest_node.prereq_node_ids:
                            edge_node = get_object_or_404(
                                CytoElement,
                                data_source_id=prereq_node_id,
                                data_target_id=quest_node.id)
                            edge_node.delete()

                    # 4. add edges between common prereqs and campaign/compound/parent node
                    CytoElement.objects.get_or_create(
                        scape=self,
                        group=CytoElement.EDGES,
                        data_source_id=prereq_node_id,
                        data_target_id=campaign.node_id,
                        # defaults={'attribute': value},
                    )

                    # 6. add invisible edge (for structure) from prereqs to first node
                    CytoElement.objects.get_or_create(
                        scape=self,
                        group=CytoElement.EDGES,
                        data_source_id=prereq_node_id,
                        data_target_id=first_node.id,
                        defaults={
                            'classes': 'hidden',
                        })

                last_node = campaign.get_last_node()
                reliant_node_ids = campaign.get_common_reliant_node_ids()
                if reliant_node_ids:
                    for reliant_node_id in reliant_node_ids:

                        # 3 remove edges between quests and common reliants
                        for quest_node in campaign.nodes:
                            # we already know all quests have this reliant node in common, so the edges should all exist
                            # unless it has an internal reliant...
                            if reliant_node_id in quest_node.reliant_node_ids:
                                edge_node = get_object_or_404(
                                    CytoElement,
                                    data_source_id=quest_node.id,
                                    data_target_id=reliant_node_id)
                                edge_node.delete()

                        # 5. add edges between campaign/compound/parent node and common reliants
                        CytoElement.objects.get_or_create(
                            scape=self,
                            group=CytoElement.EDGES,
                            data_source_id=campaign.node_id,
                            data_target_id=reliant_node_id,
                            # defaults={'attribute': value},
                        )

                        # 7. add invisible edge (for structure) from last node to reliants
                        CytoElement.objects.get_or_create(
                            scape=self,
                            group=CytoElement.EDGES,
                            data_source_id=last_node.id,
                            data_target_id=reliant_node_id,
                            defaults={
                                'classes': 'hidden',
                            }
                            # defaults={'attribute': value},
                        )

    def add_reliant(self, current_obj, mother_node):
        reliant_objects = current_obj.get_reliant_objects()
        for obj in reliant_objects:
            # mother_node
            #  > obj (reliant node 1)
            #  > obj (reliant node 2)
            #  > ...

            # create the new reliant node if it doesn't already exist
            new_node, created = self.add_node_from_object(obj)

            # if mother node is in a campaign/parent, add new_node as a reliant in the temp_campaign
            if mother_node.data_parent:
                temp_campaign = self.get_temp_campaign(
                    mother_node.data_parent.id)
                temp_campaign.add_reliant(mother_node.id, new_node.id)

            # add new_node to a campaign/compound/parent, if required
            self.add_to_campaign(obj, new_node, mother_node)

            # TODO: should add number of times prereq is required, similar to repeat edges below
            CytoElement.objects.get_or_create(
                scape=self,
                group=CytoElement.EDGES,
                data_source=mother_node,
                data_target=new_node,
                # defaults={'attribute': value},
            )

            # If repeatable, add circular edge
            # TODO: cool idea, but currently big edge gets in the way, need a tight small one.
            # if hasattr(obj, 'max_repeats'):
            #     if obj.max_repeats != 0:
            #         if obj.max_repeats < 0:
            #             label = '∞'
            #         else:
            #             label = 'x ' + str(obj.max_repeats)
            #         repeat_edge = CytoElement(
            #             scape=self, group=CytoElement.EDGES,
            #             data_source=new_node,
            #             data_target=new_node,
            #             label=label,
            #         )
            #         repeat_edge.save()

            # recursive, continue adding if this is a new node, and not a closing node
            if created and not self.is_transition_node(new_node):
                self.add_reliant(obj, new_node)

    def is_transition_node(self, node):
        """
        :return: True if node.label begins with the tilde '~' or contains an astrix '*'
        """
        if self.autobreak:
            return node.label[0] == "~" or "*" in node.label
        else:
            return False

    @staticmethod
    def generate_map(initial_object,
                     name,
                     parent_scape=None,
                     container_element_id="cy",
                     autobreak=True):

        if parent_scape:
            style_set = parent_scape.style_set
        else:
            style_set, created = CytoStyleSet.objects.get_or_create(
                name=CytoStyleSet.DEFAULT_NAME)

        scape = CytoScape(
            name=name,
            initial_content_object=initial_object,
            parent_scape=parent_scape,
            container_element_id=container_element_id,
            style_set=style_set,
            autobreak=autobreak,
        )
        scape.save()
        scape.calculate_nodes()
        return scape

    def calculate_nodes(self):
        # Create the starting node from the initial quest
        mother_node, created = self.add_node_from_object(
            self.initial_content_object, initial_node=True)
        # Temp campaign list used to track funky edges required for compound nodes to display properly with dagre
        self.init_temp_campaign_list()
        # Add nodes reliant on the mother_node, this is recursive and will generate all nodes until endpoints reached
        # Endpoints... not sure yet, but probably quests starting with '~' tilde character, or add a new field?
        self.add_reliant(self.initial_content_object, mother_node)
        # Add those funky edges for proper display of compound (parent) nodes in cyto dagre layout
        self.fix_nonsequential_campaign_edges()
        self.last_regeneration = timezone.now()
        self.save()

    def regenerate(self):
        # Delete existing nodes
        CytoElement.objects.all_for_scape(self).delete()
        self.calculate_nodes()
Esempio n. 10
0
def has_long_title(user):
    return models.Q(title__regex=r'.{10}.*')
Esempio n. 11
0
def has_region(user):
    """
    Check if user has rights to region.
    """
    return models.Q(id__in=user.regions_ids)
Esempio n. 12
0
def is_collabolator(user):
    return models.Q(collaborators=user)
Esempio n. 13
0
def is_author(user):
    return models.Q(author=user)
Esempio n. 14
0
 def search(self, query):
     return self.get_queryset().filter(models.Q(name_icontains=query))
Esempio n. 15
0
def indicator_get_defined_targets_filter():
    """returns a set of filters that filter out indicators that do not have all defined targets
        this version is used for an indicator_set that has been annotated with program_months
        (see get_program_months_annotation)"""
    filters = []
    # LOP indicators require a defined lop_target:
    filters.append(models.Q(target_frequency=Indicator.LOP) & models.Q(lop_target__isnull=False))
    # MID_END indicators require 2 defined targets (mid and end):
    filters.append(models.Q(target_frequency=Indicator.MID_END) &
                   models.Q(defined_targets__isnull=False) &
                   models.Q(defined_targets__gte=2))
    # EVENT indicators require at least 1 defined target:
    filters.append(models.Q(target_frequency=Indicator.EVENT) &
                   models.Q(defined_targets__isnull=False) &
                   models.Q(defined_targets__gte=1))
    # TIME_AWARE indicators need a number of indicators defined by the annotation on the program:
    # note the program_months field annotation is required for this annotation to succeed
    for frequency, month_count in TIME_AWARE_FREQUENCIES:
        period_count_filter = models.Q(defined_targets__gte=models.F('program_months') / month_count)
        filters.append(models.Q(target_frequency=frequency) &
                       models.Q(defined_targets__isnull=False) &
                       period_count_filter)
    combined_filter = filters.pop()
    for filt in filters:
        combined_filter |= filt
    return combined_filter
Esempio n. 16
0
 def file_size(self):
     queryset = self.values.filter(
         snapshot=None).exclude(models.Q(file='') | models.Q(file=None))
     return sum([value.file.size for value in queryset])
Esempio n. 17
0
def indicator_lop_annotations():
    """generates annotations for LOP target and actual data

    takes into account cumulative/noncumulative and number/percent"""
    # we only want targets that are either time naive or for completed periods:
    data_subquery = CollectedData.objects.filter(
        periodic_target_id=models.OuterRef('pk')
    ).order_by().values('id')
    indicator_targets = PeriodicTarget.objects.annotate(
        data_count=models.Subquery(
            data_subquery.annotate(total=models.Count('achieved')).values('total')[:1],
            output_field=models.IntegerField()
        )
    ).filter(
        models.Q(indicator=models.OuterRef('pk')),
        (
            models.Q(indicator__target_frequency__in=[Indicator.LOP, Indicator.MID_END, Indicator.EVENT]) &
            models.Q(data_count__gt=0)
        ) | models.Q(end_date__lte=models.functions.Now())
    )
    indicator_data = CollectedData.objects.filter(
        models.Q(indicator=models.OuterRef('pk'))
    )
    lop_target_sum = models.Case(
        models.When(
            # the only target for a LOP indicator is the "lop_target" value on the indicator itself:
            target_frequency=Indicator.LOP,
            then=models.ExpressionWrapper(
                models.F('lop_target'),
                output_field=models.FloatField()
            )
        ),
        models.When(
            # cumulative indicator means sort and take the most recent:
            is_cumulative=True,
            then=models.Case(
                # midline/endling and event indicators sort on customsort (with fallbacks)
                models.When(
                    target_frequency__in=[Indicator.MID_END, Indicator.EVENT],
                    then=models.Subquery(
                        indicator_targets.order_by(
                            '-customsort', '-end_date', '-create_date'
                        ).values('target')[:1],
                        output_field=models.FloatField()
                    )
                ),
                # not midline/endline means it's time-aware, sort on end_date:
                default=models.Subquery(
                    indicator_targets.order_by('-end_date').values('target')[:1],
                    output_field=models.FloatField())
                )
        ),
        default=models.Subquery(
            indicator_targets.order_by().values(
                'indicator_id'
            ).annotate(
                total=models.Sum('target')
            ).values('total'),
            output_field=models.FloatField()
        )
    )
    # lop_actual_sum = sum of all the data collected:
    lop_actual_sum = models.Case(
        models.When(
            unit_of_measure_type=Indicator.PERCENTAGE,
            then=Round(
                models.Subquery(
                    indicator_data.order_by(
                        '-date_collected'
                    ).values('achieved')[:1],
                    output_field=models.FloatField()
                    )
                )
            ),
        default=models.Subquery(
            indicator_data.order_by().values(
                'indicator_id'
            ).annotate(
                total=models.Sum('achieved')
            ).values('total'),
            output_field=models.FloatField()
        )
    )
    return {
        'lop_target_sum': lop_target_sum,
        'lop_actual_sum': lop_actual_sum,
    }
Esempio n. 18
0
    def get_query_set(self):
        use_distinct = False

        qs = self.root_query_set
        lookup_params = self.params.copy()  # a dictionary of the query string
        for i in (ALL_VAR, ORDER_VAR, ORDER_TYPE_VAR, SEARCH_VAR, IS_POPUP_VAR,
                  TO_FIELD_VAR):
            if i in lookup_params:
                del lookup_params[i]
        for key, value in lookup_params.items():
            if not isinstance(key, str):
                # 'key' will be used as a keyword argument later, so Python
                # requires it to be a string.
                del lookup_params[key]
                lookup_params[smart_str(key)] = value

            if not use_distinct:
                # Check if it's a relationship that might return more than one
                # instance
                field_name = key.split('__', 1)[0]
                try:
                    f = self.lookup_opts.get_field_by_name(field_name)[0]
                except models.FieldDoesNotExist:
                    raise IncorrectLookupParameters
                use_distinct = field_needs_distinct(f)

            # if key ends with __in, split parameter into separate values
            if key.endswith('__in'):
                value = value.split(',')
                lookup_params[key] = value

            # if key ends with __isnull, special case '' and false
            if key.endswith('__isnull'):
                if value.lower() in ('', 'false'):
                    value = False
                else:
                    value = True
                lookup_params[key] = value

            if not self.model_admin.lookup_allowed(key, value):
                raise SuspiciousOperation("Filtering by %s not allowed" % key)

        # Apply lookup parameters from the query string.
        try:
            qs = qs.filter(**lookup_params)
        # Naked except! Because we don't have any other way of validating "params".
        # They might be invalid if the keyword arguments are incorrect, or if the
        # values are not in the correct type, so we might get FieldError, ValueError,
        # ValicationError, or ? from a custom field that raises yet something else
        # when handed impossible data.
        except:
            raise IncorrectLookupParameters

        # Use select_related() if one of the list_display options is a field
        # with a relationship and the provided queryset doesn't already have
        # select_related defined.
        if not qs.query.select_related:
            if self.list_select_related:
                qs = qs.select_related()
            else:
                for field_name in self.list_display:
                    try:
                        f = self.lookup_opts.get_field(field_name)
                    except models.FieldDoesNotExist:
                        pass
                    else:
                        if isinstance(f.rel, models.ManyToOneRel):
                            qs = qs.select_related()
                            break

        # Set ordering.
        if self.order_field:
            qs = qs.order_by(
                '%s%s' %
                ((self.order_type == 'desc' and '-' or ''), self.order_field))

        # Apply keyword searches.
        def construct_search(field_name):
            if field_name.startswith('^'):
                return "%s__istartswith" % field_name[1:]
            elif field_name.startswith('='):
                return "%s__iexact" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__icontains" % field_name

        if self.search_fields and self.query:
            orm_lookups = [
                construct_search(str(search_field))
                for search_field in self.search_fields
            ]
            for bit in self.query.split():
                or_queries = [
                    models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups
                ]
                qs = qs.filter(reduce(operator.or_, or_queries))
            if not use_distinct:
                for search_spec in orm_lookups:
                    field_name = search_spec.split('__', 1)[0]
                    f = self.lookup_opts.get_field_by_name(field_name)[0]
                    if field_needs_distinct(f):
                        use_distinct = True
                        break

        if use_distinct:
            return qs.distinct()
        else:
            return qs
Esempio n. 19
0
def today_callable_q():
    return models.Q(last_action__gte=datetime.datetime.today())
 def hugs_come_and_gone(self):
     return Hug.objects.filter(models.Q(source=self.user) | models.Q(target=self.user)).order_by('-timestamp')
Esempio n. 21
0
 def mine(self, user):
     return self.get_queryset().filter(
         models.Q(sender=user) | models.Q(receiver=user))
Esempio n. 22
0
 def _get_related_jobs(self):
     return UnifiedJob.objects.non_polymorphic().filter(
         models.Q(Job___project=self)
         | models.Q(ProjectUpdate___project=self))
Esempio n. 23
0
 class Meta:
     constraints = [
         models.CheckConstraint(check=models.Q(age__gte=18),
                                name='is_adult')
     ]
class Migration(migrations.Migration):
    initial = True

    dependencies = []

    operations = [
        migrations.CreateModel(
            name='Company',
            fields=[
                ('created',
                 model_utils.fields.AutoCreatedField(
                     default=django.utils.timezone.now,
                     editable=False,
                     verbose_name='created')),
                ('modified',
                 model_utils.fields.AutoLastModifiedField(
                     default=django.utils.timezone.now,
                     editable=False,
                     verbose_name='modified')),
                ('id',
                 models.UUIDField(default=uuid.uuid4,
                                  primary_key=True,
                                  serialize=False)),
                ('name', models.TextField()),
                ('location', models.TextField()),
                ('slogan', models.TextField(blank=True, default='')),
                ('logo_url', models.URLField(blank=True, default='')),
            ],
            options={
                'abstract': False,
            },
        ),
        migrations.CreateModel(
            name='CompanyUserPermissions',
            fields=[
                ('created',
                 model_utils.fields.AutoCreatedField(
                     default=django.utils.timezone.now,
                     editable=False,
                     verbose_name='created')),
                ('modified',
                 model_utils.fields.AutoLastModifiedField(
                     default=django.utils.timezone.now,
                     editable=False,
                     verbose_name='modified')),
                ('id',
                 models.UUIDField(default=uuid.uuid4,
                                  primary_key=True,
                                  serialize=False)),
                ('is_admin', models.BooleanField(default=False)),
                ('can_edit', models.BooleanField(default=False)),
                ('can_create_jobs', models.BooleanField(default=False)),
                ('company',
                 models.ForeignKey(on_delete=django.db.models.deletion.CASCADE,
                                   related_name='company_user_permissions',
                                   to='api.company')),
            ],
            options={
                'abstract': False,
            },
        ),
        migrations.CreateModel(
            name='User',
            fields=[
                ('created',
                 model_utils.fields.AutoCreatedField(
                     default=django.utils.timezone.now,
                     editable=False,
                     verbose_name='created')),
                ('modified',
                 model_utils.fields.AutoLastModifiedField(
                     default=django.utils.timezone.now,
                     editable=False,
                     verbose_name='modified')),
                ('id',
                 models.UUIDField(default=uuid.uuid4,
                                  primary_key=True,
                                  serialize=False)),
                ('name', models.TextField()),
                ('email', models.EmailField(max_length=254)),
                ('auth0_id', models.TextField()),
                ('linkedin_id', models.TextField()),
                ('github_username', models.TextField(blank=True, default='')),
                ('is_developer', models.BooleanField(default=False)),
                ('location', models.TextField()),
                ('avatar_url', models.URLField(blank=True, default='')),
                ('languages',
                 django.contrib.postgres.fields.ArrayField(
                     base_field=models.TextField(), size=None)),
                ('skills',
                 django.contrib.postgres.fields.ArrayField(
                     base_field=models.TextField(), size=None)),
                ('companies',
                 models.ManyToManyField(through='api.CompanyUserPermissions',
                                        to='api.Company')),
            ],
        ),
        migrations.CreateModel(
            name='Job',
            fields=[
                ('created',
                 model_utils.fields.AutoCreatedField(
                     default=django.utils.timezone.now,
                     editable=False,
                     verbose_name='created')),
                ('modified',
                 model_utils.fields.AutoLastModifiedField(
                     default=django.utils.timezone.now,
                     editable=False,
                     verbose_name='modified')),
                ('id',
                 models.UUIDField(default=uuid.uuid4,
                                  primary_key=True,
                                  serialize=False)),
                ('title', models.TextField()),
                ('location', models.TextField()),
                ('description', models.TextField()),
                ('skills',
                 django.contrib.postgres.fields.ArrayField(
                     base_field=models.TextField(), size=None)),
                ('company',
                 models.ForeignKey(on_delete=django.db.models.deletion.CASCADE,
                                   related_name='jobs',
                                   to='api.company')),
            ],
            options={
                'abstract': False,
            },
        ),
        migrations.AddField(
            model_name='companyuserpermissions',
            name='user',
            field=models.ForeignKey(
                on_delete=django.db.models.deletion.CASCADE,
                related_name='company_user_permissions',
                to='api.user'),
        ),
        migrations.AddField(
            model_name='company',
            name='users',
            field=models.ManyToManyField(through='api.CompanyUserPermissions',
                                         to='api.User'),
        ),
        migrations.AddConstraint(
            model_name='user',
            constraint=models.CheckConstraint(
                check=models.Q(
                    ('is_developer', False),
                    models.Q(('is_developer', True),
                             models.Q(_negated=True,
                                      github_username__exact='')),
                    _connector='OR'),
                name='required_developer_fields'),
        ),
        migrations.AddConstraint(
            model_name='user',
            constraint=models.UniqueConstraint(condition=models.Q(
                _negated=True, github_username__exact=''),
                                               fields=('github_username', ),
                                               name='unique_github_username'),
        ),
    ]
class Migration(migrations.Migration):

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
    ]

    operations = [
        migrations.CreateModel(
            name='Game',
            fields=[
                ('id',
                 models.AutoField(auto_created=True,
                                  primary_key=True,
                                  serialize=False,
                                  verbose_name='ID')),
                ('date',
                 models.DateTimeField(default=django.utils.timezone.now)),
                ('game_map',
                 models.CharField(choices=[('Tharsis', 'Tharsis'),
                                           ('Elysium', 'Elysium'),
                                           ('Hellas', 'Hellas')],
                                  default='Tharsis',
                                  max_length=16)),
                ('draft_variant', models.BooleanField(default=True)),
                ('prelude', models.BooleanField(default=False)),
                ('venus_next', models.BooleanField(default=False)),
                ('colonies', models.BooleanField(default=False)),
            ],
        ),
        migrations.CreateModel(
            name='Player',
            fields=[
                ('id',
                 models.AutoField(auto_created=True,
                                  primary_key=True,
                                  serialize=False,
                                  verbose_name='ID')),
                ('nickname', models.CharField(max_length=32, unique=True)),
                ('motto',
                 models.CharField(blank=True, max_length=128, null=True)),
                ('user',
                 models.OneToOneField(
                     blank=True,
                     null=True,
                     on_delete=django.db.models.deletion.CASCADE,
                     to=settings.AUTH_USER_MODEL)),
            ],
        ),
        migrations.CreateModel(
            name='PlayerScore',
            fields=[
                ('id',
                 models.AutoField(auto_created=True,
                                  primary_key=True,
                                  serialize=False,
                                  verbose_name='ID')),
                ('corporation',
                 models.CharField(choices=[
                     ('Aphrodite', 'Aphrodite'), ('Aridor', 'Aridor'),
                     ('Arklight', 'Arklight'), ('Celestic', 'Celestic'),
                     ('Cheung Shing Mars', 'Cheung Shing Mars'),
                     ('Credicor', 'Credicor'), ('Ecoline', 'Ecoline'),
                     ('Helion', 'Helion'),
                     ('Interplanetary Cinematics',
                      'Interplanetary Cinematics'), ('Inventrix', 'Inventrix'),
                     ('Manutech', 'Manutech'),
                     ('Mining Guild', 'Mining Guild'),
                     ('Morning Star Inc.', 'Morning Star Inc.'),
                     ('Phobolog', 'Phobolog'), ('Point Luna', 'Point Luna'),
                     ('Polyphemos', 'Polyphemos'), ('Poseidon', 'Poseidon'),
                     ('Robinson Industries', 'Robinson Industries'),
                     ('Saturn Systems', 'Saturn Systems'),
                     ('Storm Craft Incorporated', 'Storm Craft Incorporated'),
                     ('Terractor', 'Terractor'),
                     ('Tharsis Republic', 'Tharsis Republic'),
                     ('Thorgate', 'Thorgate'),
                     ('United Nations Mars Initiative',
                      'United Nations Mars Initiative'),
                     ('Valley Trust', 'Valley Trust'), ('Viron', 'Viron'),
                     ('Vitor', 'Vitor')
                 ],
                                  max_length=64)),
                ('terraform_rating',
                 models.PositiveSmallIntegerField(default=20)),
                ('milestones', models.PositiveSmallIntegerField(default=0)),
                ('awards', models.PositiveSmallIntegerField(default=0)),
                ('greeneries', models.PositiveSmallIntegerField(default=0)),
                ('cities', models.PositiveSmallIntegerField(default=0)),
                ('event_cards', models.SmallIntegerField(default=0)),
                ('automated_cards', models.SmallIntegerField(default=0)),
                ('active_cards', models.SmallIntegerField(default=0)),
                ('resources', models.SmallIntegerField(default=0)),
                ('game',
                 models.ForeignKey(on_delete=django.db.models.deletion.CASCADE,
                                   related_name='scores',
                                   to='mars_api.game')),
                ('player',
                 models.ForeignKey(
                     null=True,
                     on_delete=django.db.models.deletion.SET_NULL,
                     related_name='scores',
                     to='mars_api.player')),
            ],
            options={
                'default_related_name': 'scores',
            },
        ),
        migrations.AddConstraint(
            model_name='game',
            constraint=models.CheckConstraint(
                check=models.Q(game_map__in={'Hellas', 'Tharsis', 'Elysium'}),
                name="Only {'Hellas', 'Elysium', 'Tharsis'} maps are allowed."
            ),
        ),
        migrations.AddConstraint(
            model_name='playerscore',
            constraint=models.UniqueConstraint(
                fields=('player', 'game'),
                name='one_score_per_player_per_game'),
        ),
        migrations.AddConstraint(
            model_name='playerscore',
            constraint=models.UniqueConstraint(
                fields=('corporation', 'game'),
                name='only_unique_corporations_per_game'),
        ),
        migrations.AddConstraint(
            model_name='playerscore',
            constraint=models.CheckConstraint(
                check=models.Q(
                    corporation__in={
                        'Celestic', 'Thorgate', 'Cheung Shing Mars',
                        'Poseidon', 'Storm Craft Incorporated', 'Helion',
                        'Inventrix', 'Aridor', 'Valley Trust', 'Viron',
                        'Robinson Industries',
                        'United Nations Mars Initiative', 'Vitor',
                        'Point Luna', 'Arklight', 'Aphrodite', 'Polyphemos',
                        'Phobolog', 'Manutech', 'Terractor', 'Ecoline',
                        'Tharsis Republic', 'Morning Star Inc.',
                        'Mining Guild', 'Saturn Systems',
                        'Interplanetary Cinematics', 'Credicor'
                    }),
                name='Only defined corporations are allowed.'),
        ),
        migrations.RemoveConstraint(
            model_name='game',
            name="Only {'Hellas', 'Elysium', 'Tharsis'} maps are allowed.",
        ),
        migrations.AddConstraint(
            model_name='game',
            constraint=models.CheckConstraint(
                check=models.Q(game_map__in={'Hellas', 'Tharsis', 'Elysium'}),
                name="Only {'Elysium', 'Hellas', 'Tharsis'} maps are allowed."
            ),
        ),
        migrations.RemoveConstraint(
            model_name='game',
            name="Only {'Elysium', 'Hellas', 'Tharsis'} maps are allowed.",
        ),
        migrations.AddConstraint(
            model_name='game',
            constraint=models.CheckConstraint(
                check=models.Q(game_map__in={'Hellas', 'Tharsis', 'Elysium'}),
                name="Only {'Hellas', 'Elysium', 'Tharsis'} maps are allowed."
            ),
        ),
        migrations.RemoveConstraint(
            model_name='game',
            name="Only {'Hellas', 'Elysium', 'Tharsis'} maps are allowed.",
        ),
        migrations.AddConstraint(
            model_name='game',
            constraint=models.CheckConstraint(
                check=models.Q(game_map__in={'Hellas', 'Tharsis', 'Elysium'}),
                name="Only {'Elysium', 'Hellas', 'Tharsis'} maps are allowed."
            ),
        ),
        migrations.RemoveConstraint(
            model_name='game',
            name="Only {'Elysium', 'Hellas', 'Tharsis'} maps are allowed.",
        ),
        migrations.AddConstraint(
            model_name='game',
            constraint=models.CheckConstraint(
                check=models.Q(game_map__in={'Hellas', 'Tharsis', 'Elysium'}),
                name="Only {'Hellas', 'Elysium', 'Tharsis'} maps are allowed."
            ),
        ),
        migrations.RemoveConstraint(
            model_name='game',
            name="Only {'Hellas', 'Elysium', 'Tharsis'} maps are allowed.",
        ),
        migrations.AddConstraint(
            model_name='game',
            constraint=models.CheckConstraint(
                check=models.Q(game_map__in={'Hellas', 'Tharsis', 'Elysium'}),
                name="Only {'Elysium', 'Hellas', 'Tharsis'} maps are allowed."
            ),
        ),
        migrations.RemoveConstraint(
            model_name='game',
            name="Only {'Elysium', 'Hellas', 'Tharsis'} maps are allowed.",
        ),
        migrations.AddConstraint(
            model_name='game',
            constraint=models.CheckConstraint(
                check=models.Q(game_map__in={'Hellas', 'Tharsis', 'Elysium'}),
                name="Only {'Elysium', 'Tharsis', 'Hellas'} maps are allowed."
            ),
        ),
        migrations.RemoveConstraint(
            model_name='game',
            name="Only {'Elysium', 'Tharsis', 'Hellas'} maps are allowed.",
        ),
        migrations.AddConstraint(
            model_name='game',
            constraint=models.CheckConstraint(
                check=models.Q(game_map__in={'Hellas', 'Tharsis', 'Elysium'}),
                name='Only defined maps are allowed.'),
        ),
        migrations.RemoveConstraint(
            model_name='playerscore',
            name='Only defined corporations are allowed.',
        ),
        migrations.AddField(
            model_name='game',
            name='number_of_generations',
            field=models.PositiveSmallIntegerField(default=10),
        ),
        migrations.AlterField(
            model_name='playerscore',
            name='corporation',
            field=models.CharField(choices=[
                ('Aphrodite', 'Aphrodite'),
                ('Aridor', 'Aridor'), ('Arklight', 'Arklight'),
                ('Celestic', 'Celestic'),
                ('Cheung Shing Mars', 'Cheung Shing Mars'),
                ('Credicor', 'Credicor'), ('Ecoline', 'Ecoline'),
                ('Helion', 'Helion'),
                ('Interplanetary Cinematics', 'Interplanetary Cinematics'),
                ('Inventrix', 'Inventrix'), ('N/A', 'N/A'),
                ('Manutech', 'Manutech'), ('Mining Guild', 'Mining Guild'),
                ('Morning Star Inc.', 'Morning Star Inc.'),
                ('Phobolog', 'Phobolog'), ('Point Luna', 'Point Luna'),
                ('Polyphemos', 'Polyphemos'), ('Poseidon', 'Poseidon'),
                ('Robinson Industries', 'Robinson Industries'),
                ('Saturn Systems', 'Saturn Systems'),
                ('Storm Craft Incorporated', 'Storm Craft Incorporated'),
                ('Teractor', 'Teractor'),
                ('Tharsis Republic', 'Tharsis Republic'),
                ('Thorgate', 'Thorgate'),
                ('United Nations Mars Initiative',
                 'United Nations Mars Initiative'),
                ('Valley Trust', 'Valley Trust'), ('Viron', 'Viron'),
                ('Vitor', 'Vitor')
            ],
                                   max_length=64),
        ),
        migrations.AddConstraint(
            model_name='playerscore',
            constraint=models.CheckConstraint(
                check=models.Q(
                    corporation__in={
                        'Celestic', 'Thorgate', 'Poseidon',
                        'Cheung Shing Mars', 'Storm Craft Incorporated',
                        'Helion', 'Inventrix', 'Aridor', 'Valley Trust',
                        'Viron', 'Robinson Industries', 'Teractor',
                        'United Nations Mars Initiative', 'Vitor',
                        'Point Luna', 'Arklight', 'Aphrodite', 'Phobolog',
                        'Polyphemos', 'Manutech', 'N/A', 'Ecoline',
                        'Tharsis Republic', 'Morning Star Inc.',
                        'Mining Guild', 'Saturn Systems',
                        'Interplanetary Cinematics', 'Credicor'
                    }),
                name='Only defined corporations are allowed.'),
        ),
        migrations.RemoveConstraint(
            model_name='playerscore',
            name='only_unique_corporations_per_game',
        ),
        migrations.AddConstraint(
            model_name='playerscore',
            constraint=models.UniqueConstraint(
                condition=models.Q(_negated=True,
                                   corporation__startswith='N/A'),
                fields=('corporation', 'game'),
                name='only_unique_corporations_per_game'),
        ),
        migrations.RemoveConstraint(
            model_name='playerscore',
            name='only_unique_corporations_per_game',
        ),
        migrations.AddConstraint(
            model_name='playerscore',
            constraint=models.UniqueConstraint(
                fields=('corporation', 'game'),
                name='only_unique_corporations_per_game'),
        ),
        migrations.RemoveConstraint(
            model_name='playerscore',
            name='only_unique_corporations_per_game',
        ),
        migrations.AddConstraint(
            model_name='playerscore',
            constraint=models.UniqueConstraint(
                condition=models.Q(_negated=True,
                                   corporation__startswith='N/A'),
                fields=('corporation', 'game'),
                name='only_unique_corporations_per_game'),
        ),
    ]
Esempio n. 26
0
 def between(self, user1, user2):
     return self.filter(
         models.Q(user1=user1, user2=user2)
         | models.Q(user1=user2, user2=user1))
Esempio n. 27
0
    def _delete(self, destroy=True, cascade=True, systemdataset=None):
        """
        Some places reference a path which will not cascade delete
        We need to manually find all paths within this volume mount point
        """
        from freenasUI.services.models import iSCSITargetExtent

        # If we are using this volume to store collectd data
        # the service needs to be restarted
        if systemdataset and systemdataset.sys_rrd_usedataset:
            reload_collectd = True
        else:
            reload_collectd = False

        # TODO: This is ugly.
        svcs = ('cifs', 'afp', 'nfs', 'iscsitarget', 'jails', 'collectd')
        reloads = (False, False, False, False, False, reload_collectd)

        n = notifier()
        if cascade:

            reloads = map(sum, zip(reloads, self.delete_attachments()))

            zvols = n.list_zfs_vols(self.vol_name)
            for zvol in zvols:
                qs = iSCSITargetExtent.objects.filter(
                    iscsi_target_extent_path='zvol/' + zvol,
                    iscsi_target_extent_type='ZVOL')
                if qs.exists():
                    if destroy:
                        notifier().destroy_zfs_vol(zvol)
                    qs.delete()
                reloads = map(
                    sum,
                    zip(reloads,
                        (False, False, False, True, False, reload_collectd)))

        else:

            attachments = self.has_attachments()
            reloads = map(
                sum, zip(reloads, [len(attachments[svc]) for svc in svcs]))

        # Delete scheduled snapshots for this volume
        Task.objects.filter(
            models.Q(task_filesystem=self.vol_name)
            | models.Q(task_filesystem__startswith="%s/" %
                       self.vol_name)).delete()

        for (svc, dirty) in zip(svcs, reloads):
            if dirty:
                n.stop(svc)

        n.detach_volume_swaps(self)

        # Ghosts volumes, does not exists anymore but is in database
        ghost = False
        try:
            status = n.get_volume_status(self.vol_name, self.vol_fstype)
            ghost = status == 'UNKNOWN'
        except:
            ghost = True

        if ghost:
            pass
        elif destroy:
            n.destroy("volume", self)
        else:
            n.volume_detach(self)

        return (svcs, reloads)
Esempio n. 28
0
 def for_user(self, user):
     return self.filter(models.Q(user1=user) | models.Q(user2=user))
Esempio n. 29
0
 def queryset(self, request):
     qs = super(PostAdmin, self).queryset(request)
     if request.user.is_superuser:
         return qs
     return qs.filter(
         models.Q(user=request.user) | models.Q(author=request.user))
Esempio n. 30
0
    def create(self, validated_data):
        """
        Create an Order and charge the user.
        """
        user = self.context['request'].user
        # if validated_data.get('target_user', None):
        #     if user.is_staff:
        #         user = validated_data.pop('target_user')
        #     else:
        #         raise serializers.ValidationError({
        #             'non_field_errors': [_(
        #                "You cannot create an order for another user without "
        #                 "admin rights."
        #             )]
        #         })
        orderlines_data = validated_data.pop('order_lines')
        payment_token = validated_data.pop('payment_token', None)
        single_use_token = validated_data.pop('single_use_token', None)
        # Temporary IDs until the external profile is created.
        validated_data['authorization_id'] = "0"
        validated_data['settlement_id'] = "0"
        validated_data['reference_number'] = "0"
        validated_data['transaction_date'] = timezone.now()
        validated_data['user'] = user
        profile = PaymentProfile.objects.filter(owner=user).first()

        retreat_reservations = list()

        if single_use_token and not profile:
            # Create external profile
            try:
                create_profile_response = create_external_payment_profile(user)
            except PaymentAPIError as err:
                raise serializers.ValidationError({'non_field_errors': [err]})
            # Create local profile
            profile = PaymentProfile.objects.create(
                name="Paysafe",
                owner=user,
                external_api_id=create_profile_response.json()['id'],
                external_api_url='{0}{1}'.format(
                    create_profile_response.url,
                    create_profile_response.json()['id']))

        with transaction.atomic():
            coupon = validated_data.pop('coupon', None)
            order = Order.objects.create(**validated_data)
            charge_response = None
            discount_amount = 0
            for orderline_data in orderlines_data:
                OrderLine.objects.create(order=order, **orderline_data)

            if coupon:
                coupon_info = validate_coupon_for_order(coupon, order)
                if coupon_info['valid_use']:
                    coupon_user = CouponUser.objects.get(
                        user=user,
                        coupon=coupon,
                    )
                    coupon_user.uses = coupon_user.uses + 1
                    coupon_user.save()
                    discount_amount = coupon_info['value']
                    orderline_cost = coupon_info['orderline'].cost
                    coupon_info['orderline'].cost = (orderline_cost -
                                                     discount_amount)
                    coupon_info['orderline'].coupon = coupon
                    coupon_info['orderline'].coupon_real_value = coupon_info[
                        'value']
                    coupon_info['orderline'].save()
                else:
                    raise serializers.ValidationError(coupon_info['error'])

            amount = order.total_cost
            tax = amount * Decimal(repr(TAX_RATE))
            tax = tax.quantize(Decimal('0.01'))
            amount *= Decimal(repr(TAX_RATE + 1))
            amount = round(amount * 100, 2)

            membership_orderlines = order.order_lines.filter(
                content_type__model="membership")
            package_orderlines = order.order_lines.filter(
                content_type__model="package")
            reservation_orderlines = order.order_lines.filter(
                content_type__model="timeslot")
            retreat_orderlines = order.order_lines.filter(
                content_type__model="retreat")
            need_transaction = False

            if membership_orderlines:
                need_transaction = True
                today = timezone.now().date()
                if user.membership and user.membership_end > today:
                    raise serializers.ValidationError({
                        'non_field_errors':
                        [_("You already have an active membership.")]
                    })
                user.membership = membership_orderlines[0].content_object
                user.membership_end = (timezone.now().date() +
                                       user.membership.duration)
                user.save()

                membership_coupons = MembershipCoupon.objects.filter(
                    membership__pk=membership_orderlines[0].content_object.pk)

                for membership_coupon in membership_coupons:
                    coupon = Coupon.objects.create(
                        value=membership_coupon.value,
                        percent_off=membership_coupon.percent_off,
                        max_use=membership_coupon.max_use,
                        max_use_per_user=membership_coupon.max_use_per_user,
                        details=membership_coupon.details,
                        start_time=timezone.now(),
                        end_time=timezone.now() +
                        membership_orderlines[0].content_object.duration,
                        owner=user)
                    coupon.applicable_retreats.set(
                        membership_coupon.applicable_retreats.all())
                    coupon.applicable_timeslots.set(
                        membership_coupon.applicable_timeslots.all())
                    coupon.applicable_packages.set(
                        membership_coupon.applicable_packages.all())
                    coupon.applicable_memberships.set(
                        membership_coupon.applicable_memberships.all())
                    coupon.applicable_product_types.set(
                        membership_coupon.applicable_product_types.all())
                    coupon.generate_code()
                    coupon.save()

            if package_orderlines:
                need_transaction = True
                for package_orderline in package_orderlines:
                    user.tickets += (
                        package_orderline.content_object.reservations *
                        package_orderline.quantity)
                    user.save()
            if reservation_orderlines:
                for reservation_orderline in reservation_orderlines:
                    timeslot = reservation_orderline.content_object
                    reservations = timeslot.reservations.filter(is_active=True)
                    reserved = reservations.count()
                    if timeslot.billing_price > user.tickets:
                        raise serializers.ValidationError({
                            'non_field_errors': [
                                _("You don't have enough tickets to make this "
                                  "reservation.")
                            ]
                        })
                    if reservations.filter(user=user):
                        raise serializers.ValidationError({
                            'non_field_errors': [
                                _("You already are registered to this timeslot: "
                                  "{0}.".format(str(timeslot)))
                            ]
                        })
                    if (timeslot.period.workplace and
                            timeslot.period.workplace.seats - reserved > 0):
                        Reservation.objects.create(user=user,
                                                   timeslot=timeslot,
                                                   is_active=True)
                        # Decrement user tickets for each reservation.
                        # OrderLine's quantity and TimeSlot's price will be
                        # used in the future if we want to allow multiple
                        # reservations of the same timeslot.
                        user.tickets -= 1
                        user.save()
                    else:
                        raise serializers.ValidationError({
                            'non_field_errors': [
                                _("There are no places left in the requested "
                                  "timeslot.")
                            ]
                        })
            if retreat_orderlines:
                need_transaction = True
                if not (user.phone and user.city):
                    raise serializers.ValidationError({
                        'non_field_errors': [
                            _("Incomplete user profile. 'phone' and 'city' "
                              "field must be filled in the user profile to book "
                              "a retreat.")
                        ]
                    })

                for retreat_orderline in retreat_orderlines:
                    retreat = retreat_orderline.content_object
                    user_waiting = retreat.wait_queue.filter(user=user)
                    reservations = retreat.reservations.filter(is_active=True)
                    reserved = reservations.count()
                    if reservations.filter(user=user):
                        raise serializers.ValidationError({
                            'non_field_errors': [
                                _("You already are registered to this "
                                  "retreat: {0}.".format(str(retreat)))
                            ]
                        })
                    if (((retreat.seats - retreat.total_reservations -
                          retreat.reserved_seats) > 0)
                            or (retreat.reserved_seats
                                and WaitQueueNotification.objects.filter(
                                    user=user, retreat=retreat))):
                        retreat_reservations.append(
                            RetreatReservation.objects.create(
                                user=user,
                                retreat=retreat,
                                order_line=retreat_orderline,
                                is_active=True))
                        # Decrement reserved_seats if > 0
                        if retreat.reserved_seats:
                            retreat.reserved_seats = (retreat.reserved_seats -
                                                      1)
                            retreat.save()
                    else:
                        raise serializers.ValidationError({
                            'non_field_errors': [
                                _("There are no places left in the requested "
                                  "retreat.")
                            ]
                        })
                    if user_waiting:
                        user_waiting.delete()

            if need_transaction and payment_token and int(amount):
                # Charge the order with the external payment API
                try:
                    charge_response = charge_payment(int(round(amount)),
                                                     payment_token,
                                                     str(order.id))
                except PaymentAPIError as err:
                    raise serializers.ValidationError(
                        {'non_field_errors': [err]})

            elif need_transaction and single_use_token and int(amount):
                # Add card to the external profile & charge user
                try:
                    card_create_response = create_external_card(
                        profile.external_api_id, single_use_token)
                    charge_response = charge_payment(
                        int(round(amount)),
                        card_create_response.json()['paymentToken'],
                        str(order.id))
                except PaymentAPIError as err:
                    raise serializers.ValidationError(
                        {'non_field_errors': [err]})
            elif (membership_orderlines or package_orderlines
                  or retreat_orderlines) and int(amount):
                raise serializers.ValidationError({
                    'non_field_errors': [
                        _("A payment_token or single_use_token is required to "
                          "create an order.")
                    ]
                })

            if need_transaction:
                if charge_response:
                    charge_res_content = charge_response.json()
                    order.authorization_id = charge_res_content['id']
                    order.settlement_id = charge_res_content['settlements'][0][
                        'id']
                    order.reference_number = charge_res_content[
                        'merchantRefNum']
                else:
                    charge_res_content = {
                        'card': {
                            'lastDigits': None,
                            'type': "NONE"
                        }
                    }
                    order.authorization_id = 0
                    order.settlement_id = 0
                    order.reference_number = "charge-" + str(uuid.uuid4())
                order.save()

        if need_transaction:
            # Send order email
            orderlines = order.order_lines.filter(
                models.Q(content_type__model='membership')
                | models.Q(content_type__model='package')
                | models.Q(content_type__model='retreat'))

            # Here, the 'details' key is used to provide details of the
            #  item to the email template.
            # As of now, only 'retreat' objects have the 'email_content'
            #  key that is used here. There is surely a better way to
            #  to handle that logic that will be more generic.
            items = [
                {
                    'price':
                    orderline.content_object.price,
                    'name':
                    "{0}: {1}".format(str(orderline.content_type),
                                      orderline.content_object.name),
                    # Removed details section because it was only used
                    # for retreats. Retreats instead have another
                    # unique email containing details of the event.
                    # 'details':
                    #    orderline.content_object.email_content if hasattr(
                    #         orderline.content_object, 'email_content'
                    #     ) else ""
                } for orderline in orderlines
            ]

            # Send order confirmation email
            merge_data = {
                'STATUS': "APPROUVÉE",
                'CARD_NUMBER': charge_res_content['card']['lastDigits'],
                'CARD_TYPE':
                PAYSAFE_CARD_TYPE[charge_res_content['card']['type']],
                'DATETIME': timezone.localtime().strftime("%x %X"),
                'ORDER_ID': order.id,
                'CUSTOMER_NAME': user.first_name + " " + user.last_name,
                'CUSTOMER_EMAIL': user.email,
                'CUSTOMER_NUMBER': user.id,
                'AUTHORIZATION': order.authorization_id,
                'TYPE': "Achat",
                'ITEM_LIST': items,
                'TAX': tax,
                'DISCOUNT': discount_amount,
                'COUPON': coupon,
                'SUBTOTAL': round(amount / 100 - tax, 2),
                'COST': round(amount / 100, 2),
            }

            plain_msg = render_to_string("invoice.txt", merge_data)
            msg_html = render_to_string("invoice.html", merge_data)

            send_mail(
                "Confirmation d'achat",
                plain_msg,
                settings.DEFAULT_FROM_EMAIL,
                [order.user.email],
                html_message=msg_html,
            )

        # Send retreat informations emails
        for retreat_reservation in retreat_reservations:
            # Send info email
            merge_data = {
                'RETREAT': retreat_reservation.retreat,
                'USER': user,
            }

            plain_msg = render_to_string("retreat_info.txt", merge_data)
            msg_html = render_to_string("retreat_info.html", merge_data)

            send_mail(
                "Confirmation d'inscription à la retraite",
                plain_msg,
                settings.DEFAULT_FROM_EMAIL,
                [retreat_reservation.user.email],
                html_message=msg_html,
            )

        return order