Ejemplo n.º 1
0
class Survey(models.Model):
    title = models.CharField(_('survey title'), max_length=255)
    slug = models.SlugField(_('slug'), max_length=255, unique=True)
    description = models.TextField(
        verbose_name=_("description"),
        help_text=
        _("This field appears on the public web site and should give an overview to the interviewee"
          ),
        blank=True)

    ## Add validation on datetimes
    opens = models.DateTimeField(_('survey starts accepting submissions on'))
    closes = models.DateTimeField(_('survey stops accepting submissions on'))
    # Define the behavior of the survey
    visible = models.BooleanField(_('survey is visible'))
    public = models.BooleanField(_('survey results are public'))
    restricted = models.BooleanField(
        verbose_name=_("restrict the survey to authentified user"),
        blank=True,
        default=False)
    allows_multiple_interviews = models.BooleanField(
        verbose_name=_("allows multiple interviews"), blank=True, default=True)
    #    template_name = models.CharField(_('template name'),max_length=150,
    #                                     null=True, blank=True,
    #                                     help_text=_("This field is used to define a custom template "
    #                                     "(Example: 'dj_survey/template/my_add_interview_forms.html')."))

    # Control who can edit the survey
    # TODO: Plug this control in the view used to edit the survey
    created_by = models.ForeignKey(User, related_name="created_surveys")
    editable_by = models.ForeignKey(User, related_name="owned_surveys")

    # Integration in Pinax
    recipient_type = models.ForeignKey(ContentType, blank=True, null=True)
    recipient_id = models.PositiveIntegerField(blank=True, null=True)
    recipient = generic.GenericForeignKey('recipient_type', 'recipient_id')

    objects = SurveyManager()

    @property
    def _cache_name(self):
        if not self.id:
            id = 'new'
        else:
            id = int(self.id)
        return 'survey_' + repr(id) + '_status'

    @property
    def open(self):
        if not self.visible:
            return False
        value = cache.get(self._cache_name)
        if value is not None:
            return value
        now = datetime.datetime.now()
        if self.opens >= now:
            value = False
            duration = (now - self.opens).seconds
        elif self.closes >= now:
            value = True
            duration = (self.opens - now).seconds
        else:
            value = False
            duration = 60 * 60 * 24 * 31
        if duration:
            cache.set(self._cache_name, value, duration)
        return value

    @property
    def closed(self):
        return not self.open

    @property
    def status(self):
        if not self.visible: return _('private')
        if self.open: return _('open')
        if datetime.now() < self.opens:
            return unicode(_('opens ')) + datefilter(self.opens)
        return _('closed')

    @property
    def answer_count(self):
        if hasattr(self, '_answer_count'):
            return self._answer_count
        self._answer_count = sum(q.answer_count
                                 for q in self.questions.iterator())
        return self._answer_count

    @property
    def interview_count(self):
        # NOTSURE: Do we realy need this optimisation?
        if hasattr(self, '_interview_count'):
            return self._interview_count
        self._interview_count = len(
            Answer.objects.filter(
                question__survey=self.id).values('interview_uuid').distinct())
        return self._interview_count

    @property
    def session_key_count(self):
        # NOTSURE: Do we realy need this optimisation?
        if hasattr(self, '_session_key_count'):
            return self._submission_count
        self._submission_count = len(
            Answer.objects.filter(
                question__survey=self.id).values('session_key').distinct())
        return self._submission_count

    def has_answers_from(self, session_key):
        return bool(
            Answer.objects.filter(
                session_key__exact=session_key.lower(),
                question__survey__id__exact=self.id).distinct().count())

    def __unicode__(self):
        return u' - '.join([self.slug, self.title])

    @models.permalink
    def get_absolute_url(self):
        return ('survey-detail', (), {'survey_slug': self.slug})

    def save(self):
        res = super(Survey, self).save()
        cache.delete(self._cache_name)
        return res

    def answers_viewable_by(self, user):
        if not self.visible: return False
        if self.public: return True
        if user.is_anonymous(): return False
        return user.has_perm('survey.view_answers')
Ejemplo n.º 2
0
 class Model(models.Model):
     field = generic.GenericForeignKey()
Ejemplo n.º 3
0
class Message(models.Model):
    """
    A Message.

    We have a uuid, which is our reference. We also have a gateway_message_id,
    which is their reference.  This is required by some systems so we can
    pass in a unique value that will allow us to match up replies to original
    messages.
    """
    content = models.TextField(help_text=_('The body of the message.'))
    recipient_number = models.CharField(
        max_length=32,
        help_text=_(
            'The international number of the recipient, without the leading +')
    )

    sender = models.ForeignKey('auth.User', related_name='sent_sms_messages')
    sender_number = models.CharField(
        max_length=32,
        null=True,
        blank=True,
        help_text=_(
            'The international number of the sender, without the leading +'))
    send_date = models.DateTimeField(null=True, blank=True, editable=False)
    delivery_date = models.DateTimeField(null=True, blank=True, editable=False)
    uuid = uuidfield.fields.UUIDField(
        auto=True, help_text=_('Used for associating replies.'))

    status = models.CharField(max_length=16,
                              choices=MESSAGE_STATUSES,
                              default="Unsent")
    status_message = models.CharField(max_length=128, null=True, blank=True)
    billed = models.BooleanField(default=False)

    content_type = models.ForeignKey('contenttypes.ContentType')
    object_id = models.PositiveIntegerField()
    billee = generic.GenericForeignKey()

    gateway = models.ForeignKey('sms.Gateway', null=True, blank=True)
    gateway_message_id = models.CharField(max_length=128,
                                          blank=True,
                                          null=True,
                                          editable=False)

    #reply_callback = picklefield.PickledObjectField(null=True, blank=True)
    reply_callback = models.CharField(max_length=128, null=True, blank=True)
    gateway_charge = models.DecimalField(max_digits=10,
                                         decimal_places=5,
                                         null=True,
                                         blank=True)

    objects = MessageManager()

    class Meta:
        app_label = 'sms'
        permissions = (('view_message', 'Can view message'), )
        ordering = ('send_date', )

    def send(self, gateway):
        gateway.send(self)

    @property
    def length(self):
        """Unicode messages are limited to 70 chars/message segment."""
        # try:
        #     return len(str(self.content)) / 160 + 1
        # except UnicodeEncodeError:
        #     return len(self.content) / 70 + 1
        return len(self.content) / 160 + 1

    @property
    def local_send_time(self):
        if self.billee.timezone:
            return adjust_datetime_to_timezone(self.send_date,
                                               settings.TIME_ZONE,
                                               self.billee.timezone)
        return self.send_date

    def __unicode__(self):
        return "[%s] Sent to %s by %s at %s [%i]" % (
            self.status, self.recipient_number, self.sender, self.send_date,
            self.length)
Ejemplo n.º 4
0
class BlogEntry(SlugifiedModelMixin, ImagableItemMixin):
    """
    Basic class for simplified blog entries. Blog entry may be tied to another
    content, for example organization, project or location. This way we can use
    custom managers to filter content from such modules.
    """
    content = models.TextField(default="", verbose_name=_(u"content"))
    date_created = models.DateTimeField(auto_now_add=True,
                                        verbose_name=_(u"date created"))
    date_edited = models.DateTimeField(auto_now=True,
                                       verbose_name=_(u"date edited"))
    author = models.ForeignKey(User,
                               related_name="simpleblog_entries",
                               verbose_name=_(u"author"))
    category = models.ForeignKey(BlogCategory,
                                 blank=True,
                                 null=True,
                                 verbose_name=_(u"category"))
    tags = models.CharField(default="",
                            blank=True,
                            max_length=255,
                            verbose_name=_(u"tags"),
                            help_text=_(u"List of tags separated by comma"))

    # By defining generic relation we can decide where to publish this entry
    content_type = models.ForeignKey(ContentType, blank=True, null=True)
    object_id = models.PositiveIntegerField(blank=True, null=True)
    content_object = generic.GenericForeignKey('content_type', 'object_id')

    objects = BlogManager()

    def get_absolute_url(self):
        if self.content_object is not None:
            model_name = self.content_object._meta.model_name
            if model_name == 'organization':
                return reverse('organizations:news-detail',
                               kwargs={
                                   'slug': self.content_object.slug,
                                   'news_slug': self.slug,
                               })
            elif model_name == 'idea':
                return reverse('locations:idea-news-list',
                               kwargs={
                                   'location_slug':
                                   self.content_object.location.slug,
                                   'slug': self.content_object.slug,
                               })
            elif model_name == 'socialproject':
                return reverse('projects:news-detail',
                               kwargs={
                                   'slug': self.content_object.slug,
                                   'news_pk': self.pk,
                               })
        return reverse('simpleblog:detail', kwargs={'slug': self.slug})

    def save(self, *args, **kwargs):
        self.content = sanitizeHtml(self.content)
        super(BlogEntry, self).save(*args, **kwargs)

    def has_access(self, user):
        """ Check if particular user can delete/update this entry. """
        if user.is_superuser:
            return True
        return user == self.author

    def __str__(self):
        return self.name

    class Meta:
        ordering = [
            '-date_created',
        ]
        verbose_name = _(u"blog entry")
        verbose_name_plural = _(u"blog entries")
Ejemplo n.º 5
0
class CustomFieldValue(TimeStampMixin, models.Model):
    custom_field = models.ForeignKey(CustomField,
                                     verbose_name=_('key'),
                                     on_delete=models.PROTECT)
    # value is stored in charfield on purpose - ralph's custom field mechanism
    # is by-design simple, so it, for example, doesn't allow to filter by range
    # of integers or other Django filters like gte, lte.
    value = models.CharField(max_length=CUSTOM_FIELD_VALUE_MAX_LENGTH)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField(db_index=True)
    object = generic.GenericForeignKey('content_type', 'object_id')

    objects = models.Manager()
    # generic relation has to use specific manager (queryset)
    # which handle inheritance
    inherited_objects = CustomFieldValueQuerySet.as_manager()

    class Meta:
        unique_together = ('custom_field', 'content_type', 'object_id')

    def __str__(self):
        return '{} ({}): {}'.format(
            self.custom_field if self.custom_field_id else None, self.object,
            self.value)

    def _get_unique_checks(self, exclude=None):
        if exclude:
            for k in ['content_type', 'object_id']:
                try:
                    exclude.remove(k)
                except ValueError:
                    pass
        return super()._get_unique_checks()

    def unique_error_message(self, model_class, unique_check):
        """
        Return better unique validation message than standard Django message.
        """
        opts = model_class._meta

        params = {
            'model': self,
            'model_class': model_class,
            'model_name': six.text_type(capfirst(opts.verbose_name)),
            'unique_check': unique_check,
        }

        if len(unique_check) > 1:
            return ValidationError(
                message=
                _("Custom field of the same type already exists for this object."  # noqa
                  ),
                code='unique_together',
                params=params,
            )
        return super().unique_error_message(self, model_class, unique_check)

    def clean(self):
        if self.custom_field_id:
            self.custom_field.get_form_field().clean(self.value)
        super().clean()
Ejemplo n.º 6
0
class Document(ResourceBase):
    """
    A document is any kind of information that can be attached to a map such as pdf, images, videos, xls...
    """

    # Relation to the resource model
    content_type = models.ForeignKey(ContentType, blank=True, null=True)
    object_id = models.PositiveIntegerField(blank=True, null=True)
    resource = generic.GenericForeignKey('content_type', 'object_id')

    doc_file = models.FileField(upload_to='documents',
                                null=True,
                                blank=True,
                                verbose_name=_('File'))

    extension = models.CharField(max_length=128, blank=True, null=True)

    doc_url = models.URLField(
        blank=True,
        null=True,
        help_text=_('The URL of the document if it is external.'),
        verbose_name=_('URL'))

    def __unicode__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('document_detail', args=(self.id, ))

    @property
    def name_long(self):
        if not self.title:
            return str(self.id)
        else:
            return '%s (%s)' % (self.title, self.id)

    def _render_thumbnail(self):
        from cStringIO import StringIO

        size = 200, 150

        try:
            from PIL import Image, ImageOps
        except ImportError, e:
            logger.error(
                '%s: Pillow not installed, cannot generate thumbnails.' % e)
            return None

        try:
            # if wand is installed, than use it for pdf thumbnailing
            from wand import image
        except:
            wand_available = False
        else:
            wand_available = True

        if wand_available and self.extension and self.extension.lower(
        ) == 'pdf' and self.doc_file:
            logger.debug('Generating a thumbnail for document: {0}'.format(
                self.title))
            with image.Image(filename=self.doc_file.path) as img:
                img.sample(*size)
                return img.make_blob('png')
        elif self.extension and self.extension.lower(
        ) in IMGTYPES and self.doc_file:

            img = Image.open(self.doc_file.path)
            img = ImageOps.fit(img, size, Image.ANTIALIAS)
        else:
            filename = finders.find('documents/{0}-placeholder.png'.format(self.extension), False) or \
                finders.find('documents/generic-placeholder.png', False)

            if not filename:
                return None

            img = Image.open(filename)

        imgfile = StringIO()
        img.save(imgfile, format='PNG')
        return imgfile.getvalue()
Ejemplo n.º 7
0
class FullHistory(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.CharField(max_length=255)
    revision = models.PositiveIntegerField()

    content_object = generic.GenericForeignKey()

    action_time = models.DateTimeField(auto_now_add=True)
    _data = models.TextField(db_column='data')
    request = models.ForeignKey(Request, null=True, blank=True)
    site = models.ForeignKey(Site, default=Site.objects.get_current)
    action = models.CharField(max_length=1, choices=ACTIONS)
    info = models.TextField()

    objects = FullHistoryManager()

    def set_data(self, val):
        self._data = ENCODER.encode(val)

    def get_data(self):
        return simplejson.loads(self._data)

    data = property(get_data, set_data)

    def action_display(self):
        return dict(ACTIONS)[self.action]

    def user(self):
        '''
        Returns the user entry responsible for this change
        May return User.DoesNotExist if the user was deleted
        '''
        if self.request is None:
            return None
        return self.request.user()

    def create_info(self):
        '''
        Generates a summary description of this history entry
        '''
        user_name = u'(System)'
        if self.request:
            user_name = self.request.user_name
        ret = list()
        ret.append({
            'C': u'%s Created',
            'U': u'%s Updated',
            'D': u'%s Deleted',
        }[self.action] % user_name)
        if self.action == 'U':
            for key, value in self.data.items():
                if not isinstance(value, tuple) or len(value) != 2:
                    #fix for old admin
                    continue
                ret.append(
                    u'"%s" changed from [%s] to [%s]' %
                    (key, unicode(value[0])[:50], unicode(value[1])[:50]))
        return '\n'.join(ret)

    def previous(self):
        '''
        Retrieves the previous history entry for this object
        '''
        return FullHistory.objects.get(content_type=self.content_type,
                                       object_id=self.object_id,
                                       revision=self.revision - 1)

    def next(self):
        '''
        Retrieves the next history entry for this object
        '''
        return FullHistory.objects.get(content_type=self.content_type,
                                       object_id=self.object_id,
                                       revision=self.revision + 1)

    def related_changes(self):
        '''
        Returns a queryset of the changes that have also occurred with this change
        '''
        if self.request:
            return FullHistory.objects.filter(request=self.request).exclude(
                pk=self.pk)
        return FullHistory.objects.none()

    def save(self, *args, **kwargs):
        if not self.pk:
            self.revision = len(
                FullHistory.objects.filter(content_type=self.content_type,
                                           object_id=self.object_id))
        if not self.info:
            self.info = self.create_info()
        return super(FullHistory, self).save(*args, **kwargs)

    def __unicode__(self):
        return u'%s %s %s' % (self.content_type, self.object_id,
                              self.action_time)

    objects = FullHistoryManager()

    class Meta:
        verbose_name_plural = _("full histories")
        get_latest_by = "revision"
        unique_together = (('revision', 'content_type', 'object_id'), )
Ejemplo n.º 8
0
 class Model(models.Model):
     content_type = models.IntegerField()  # should be ForeignKey
     object_id = models.PositiveIntegerField()
     content_object = generic.GenericForeignKey('content_type',
                                                'object_id')
Ejemplo n.º 9
0
 class Model(models.Model):
     content_type = models.ForeignKey(
         'self')  # should point to ContentType
     object_id = models.PositiveIntegerField()
     content_object = generic.GenericForeignKey('content_type',
                                                'object_id')
Ejemplo n.º 10
0
class BanyanUserNotifications(models.Model):
    createdAt = models.DateTimeField(auto_now_add=True)
    user = models.ForeignKey(BanyanUser,
                             related_name='notifications',
                             null=False,
                             blank=False,
                             db_index=True)
    from_user = models.ForeignKey(BanyanUser,
                                  related_name='+',
                                  null=True,
                                  blank=True)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField(db_index=True)
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    activity = models.ForeignKey('core.Activity', null=True, blank=True)
    description = models.CharField(max_length=500)
    '''
    Notification types
    '''
    LIKE_NOTIF = 'like'
    FOLLOW_NOTIF = 'follow'
    JOIN_NOTIF = 'join'
    STORY_STARTED_NOTIF = 'story_start'
    PIECE_ADDED_NOTIF = 'piece_add'
    VIEW_INVITE_NOTIF = 'view_inv'
    CONTRIB_INVITE_NOTIF = 'contrib_inv'

    NOTIFICATION_TYPE_CHOICES = ((LIKE_NOTIF, 'loves the piece'),
                                 (FOLLOW_NOTIF, 'is following'),
                                 (JOIN_NOTIF, 'has joined Banyan'),
                                 (STORY_STARTED_NOTIF,
                                  'has started story'), (PIECE_ADDED_NOTIF,
                                                         'has added piece'),
                                 (VIEW_INVITE_NOTIF,
                                  'has invited you to read'),
                                 (CONTRIB_INVITE_NOTIF,
                                  'has invited you to contribute to'))
    type = models.CharField(max_length=20,
                            choices=NOTIFICATION_TYPE_CHOICES,
                            db_index=True)
    '''
    Cache keys
    These are the cache keys related to this model
    '''
    class Meta:
        unique_together = ('user', 'from_user', 'object_id', 'content_type',
                           'type')
        ordering = ['-createdAt']

    def __unicode__(self):
        return u"{from_user} {verb} {object}".format(
            from_user=self.from_user.get_full_name(),
            verb=self.get_type_display(),
            object=unicode(self.content_object))

    @classmethod
    def bulk_save_all(cls, notifications=[]):
        for notification in notifications:
            try:
                notification.save()
            except IntegrityError:
                continue
            except:
                logger.info(
                    "accounts.models.BanyanUserNotifications::bulk_save_all error {} {} in creating notification"
                    .format(sys.exc_info()[0],
                            sys.exc_info()[1]))
                continue
Ejemplo n.º 11
0
class Activity(models.Model):
    """ Saving an activity """
    CREATE = 1
    UPDATE = 2
    DELETE = 3
    CLOSE = 4
    COMMENT = 5
    INVITE = 6
    START = 7
    ADMIN = 8
    JOIN = 9

    ACTION_CHOICES = (
        (CREATE, _('created')),
        (UPDATE, _('updated')),
        (DELETE, _('deleted')),
        (CLOSE, _('closed')),
        (COMMENT, _('commented on')),
        (INVITE, _('invited')),
        (START, _('started')),
        (ADMIN, _('permissions')),
        (JOIN, _('joined')),
    )

    actor = models.ForeignKey(User, related_name='activities')
    action = models.SmallIntegerField(_('action'), choices=ACTION_CHOICES)
    project = models.ForeignKey(Project, related_name='activities')
    time = models.DateTimeField(_('time'), auto_now_add=True)

    # Direct object
    object_id = models.PositiveIntegerField()
    content_type = models.ForeignKey(ContentType,
                                     related_name='activity_objects')
    content_object = generic.GenericForeignKey('content_type', 'object_id')

    # Indirect object
    indirect_object_id = models.PositiveIntegerField(blank=True, null=True)
    indirect_content_type = models.ForeignKey(
        ContentType,
        related_name='activity_indirect_objects',
        blank=True,
        null=True)
    indirect_content_object = generic.GenericForeignKey(
        'indirect_content_type', 'indirect_object_id')

    objects = ActivityManager()

    def __unicode__(self):
        return self.humanize(admin=True).strip()

    def save(self, *args, **kwargs):
        """
        When saving an activity e-mail notification to project members
        """
        super(Activity, self).save(*args, **kwargs)

        # Send mail as notification
        if settings.EMAIL_NOTIFICATIONS is True:
            mail_data = self.prepare_mail()
            mail_data.send()

    class Meta:
        verbose_name = _('activity')
        verbose_name_plural = _('activities')
        ordering = ['-time']

    @property
    def app_label(self):
        """ 
        Returns the ``app_label`` so we can search for the templates.
        
        """
        return self.content_type.app_label

    def _get_template_for_action(self, mail=''):
        """ Returns the template for this action """
        options = [
            '%(app_label)s/actions/%(action)s%(mail)s.txt' % {
                'app_label': self.app_label,
                'action': self.get_action_display().replace(' ', ''),
                'mail': mail,
            },
            '%(app_label)s/actions/generic%(mail)s.txt' % {
                'app_label': self.app_label,
                'mail': mail
            }, 'blactivity/generic.txt'
        ]
        t = loader.select_template(options)
        return t

    def humanize(self, admin=False, mail=False):
        """ Returns a sentence of the committed action """
        if admin:
            template = loader.get_template('blactivity/admin.txt')
        elif mail:
            template = self._get_template_for_action('_mail')
        else:
            template = self._get_template_for_action()

        context = Context({
            'actor':
            self.actor.username,
            'actor_id':
            self.actor.id,
            'action':
            self.get_action_display(),
            'project':
            self.project,
            'project_id':
            self.project.id,
            'time':
            self.time,
            'object':
            self.content_object,
            'object_id':
            self.object_id,
            'object_type':
            self.content_type,
            'indirect_object':
            self.indirect_content_object if self.indirect_object_id else None,
            'indirect_object_id':
            self.indirect_object_id if self.indirect_object_id else None,
            'MEDIA_URL':
            settings.MEDIA_URL,
        })
        sentence = template.render(context)
        return sentence

    def prepare_mail(self):
        """ Prepare mass mail """
        subject = "[%(project)s] New activity" % {'project': self.project}
        message = self.humanize(mail=True)
        from_email = settings.EMAIL_HOST_USER

        email = EmailMessage(subject, message, from_email,
                             self.recipient_list())
        email.content_subtype = "html"

        return email

    def recipient_list(self):
        """ Return list with all recipient for mail """
        recipient_list = []
        for member in self.project.members.all():
            try:
                profile = member.get_profile()
            except:
                pass
            else:
                if profile.notifications:
                    recipient_list.append(member.email)

        if len(recipient_list) > 0:
            return recipient_list
        else:
            return None
Ejemplo n.º 12
0
class MenuItem(MPTTModel):

    parent = TreeForeignKey('self',
                            null=True,
                            blank=True,
                            related_name='children')
    label = models.CharField(
        _('label'),
        max_length=255,
        help_text="The display name on the web site.",
    )
    slug = models.SlugField(
        _('slug'),
        unique=True,
        max_length=255,
        help_text="Unique identifier for this menu item (also CSS ID)")
    order = models.IntegerField(
        _('order'),
        choices=[(x, x) for x in xrange(0, 51)],
    )
    is_enabled = models.BooleanField(default=True)
    link = models.CharField(
        _('link'),
        max_length=255,
        help_text=
        "The view of the page you want to link to, as a python path or the shortened URL name.",
        blank=True,
    )
    content_type = models.ForeignKey(
        ContentType,
        null=True,
        blank=True,
    )
    object_id = models.PositiveIntegerField(
        null=True,
        blank=True,
    )
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    href = models.CharField(_('href'), editable=False, max_length=255)

    objects = MenuItemManager()
    tree = TreeManager()

    class Meta:
        ordering = ('lft', 'tree_id')

    class MPTTMeta:
        order_insertion_by = ('order', )

    def to_tree(self):
        cache_key = 'menu-tree-%s' % self.slug
        root = cache.get(cache_key)
        if not root:
            item = root = Item(self)
            descendents = self.get_descendants()
            for prev, curr, next in previous_current_next(descendents):
                previous_item = item
                item = Item(curr)
                if not prev or prev.level < curr.level:
                    previous_item.add_child(item)
                elif prev and prev.level > curr.level:
                    parent = previous_item
                    while parent.node.level >= curr.level:
                        parent = parent.parent
                    parent.add_child(item)
                else:
                    previous_item.parent.add_child(item)
            cache.set(cache_key, root)
        return root

    def save(self, *args, **kwargs):
        literal_url_prefixes = ('/', 'http://', 'https://')
        regex_url_prefixes = ('^', )
        if self.link:
            if any([self.link.startswith(s) for s in literal_url_prefixes]):
                self.href = self.link
            elif any([self.link.startswith(s) for s in regex_url_prefixes]):
                self.href = ''  # regex should not be used as an actual URL
            else:
                self.href = reverse(self.link)
        elif self.content_object:
            self.href = self.content_object.get_absolute_url()
        else:
            self.href = ''
        delete_cache()
        super(MenuItem, self).save(*args, **kwargs)

    def delete(self, *args, **kwargs):
        delete_cache()
        super(MenuItem, self).delete(*args, **kwargs)

    def __unicode__(self):
        return self.slug
Ejemplo n.º 13
0
class FreeThreadedComment(models.Model):
    """
    A threaded comment which need not be associated with an instance of 
    ``django.contrib.auth.models.User``.  Instead, it requires minimally a name,
    and maximally a name, website, and e-mail address.  It is given its hierarchy
    by a nullable relationship back on itself named ``parent``.
    
    This ``FreeThreadedComment`` supports several kinds of markup languages,
    including Textile, Markdown, and ReST.
    
    It also includes two Managers: ``objects``, which is the same as the normal
    ``objects`` Manager with a few added utility functions (see above), and
    ``public``, which has those same utility functions but limits the QuerySet to
    only those values which are designated as public (``is_public=True``).
    """
    # Generic Foreign Key Fields
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField(_('object ID'))
    content_object = generic.GenericForeignKey()
    
    # Hierarchy Field
    parent = models.ForeignKey('self', null = True, blank=True, default = None, related_name='children')
    
    # User-Replacement Fields
    name = models.CharField(_('name'), max_length = 128)
    website = models.URLField(_('site'), blank = True)
    email = models.EmailField(_('e-mail address'), blank = True)
    
    # Date Fields
    date_submitted = models.DateTimeField(_('date/time submitted'), default = datetime.now)
    date_modified = models.DateTimeField(_('date/time modified'), default = datetime.now)
    date_approved = models.DateTimeField(_('date/time approved'), default=None, null=True, blank=True)
    
    # Meat n' Potatoes
    comment = models.TextField(_('comment'))
    markup = models.IntegerField(choices=MARKUP_CHOICES, default=DEFAULT_MARKUP, null=True, blank=True)
    
    # Status Fields
    is_public = models.BooleanField(_('is public'), default = True)
    is_approved = models.BooleanField(_('is approved'), default = False)
    
    # Extra Field
    ip_address = models.IPAddressField(_('IP address'), null=True, blank=True)
    
    objects = ThreadedCommentManager()
    public = PublicThreadedCommentManager()
    
    def __unicode__(self):
        if len(self.comment) > 50:
            return self.comment[:50] + "..."
        return self.comment[:50]
    
    def save(self, **kwargs):
        if not self.markup:
            self.markup = DEFAULT_MARKUP
        self.date_modified = datetime.now()
        if not self.date_approved and self.is_approved:
            self.date_approved = datetime.now()
        super(FreeThreadedComment, self).save()
    
    def get_content_object(self, **kwargs):
        """
        Wrapper around the GenericForeignKey due to compatibility reasons
        and due to ``list_display`` limitations.
        """
        return self.content_object
    
    def get_base_data(self, show_dates=True):
        """
        Outputs a Python dictionary representing the most useful bits of
        information about this particular object instance.
        
        This is mostly useful for testing purposes, as the output from the
        serializer changes from run to run.  However, this may end up being
        useful for JSON and/or XML data exchange going forward and as the
        serializer system is changed.
        """
        markup = "plaintext"
        for markup_choice in MARKUP_CHOICES:
            if self.markup == markup_choice[0]:
                markup = markup_choice[1]
                break
        to_return = {
            'content_object' : self.content_object,
            'parent' : self.parent,
            'name' : self.name,
            'website' : self.website,
            'email' : self.email,
            'comment' : self.comment,
            'is_public' : self.is_public,
            'is_approved' : self.is_approved,
            'ip_address' : self.ip_address,
            'markup' : force_unicode(markup),
        }
        if show_dates:
            to_return['date_submitted'] = self.date_submitted
            to_return['date_modified'] = self.date_modified
            to_return['date_approved'] = self.date_approved
        return to_return
    
    class Meta:
        ordering = ('-date_submitted',)
        verbose_name = _("Free Threaded Comment")
        verbose_name_plural = _("Free Threaded Comments")
        get_latest_by = "date_submitted"
Ejemplo n.º 14
0
class Value(models.Model):
    '''
    Putting the **V** in *EAV*. This model stores the value for one particular
    :class:`Attribute` for some entity.

    As with most EAV implementations, most of the columns of this model will
    be blank, as onle one *value_* field will be used.

    Example:

    >>> import eav
    >>> from django.contrib.auth.models import User
    >>> eav.register(User)
    >>> u = User.objects.create(username='******')
    >>> a = Attribute.objects.create(name='Favorite Drink', datatype='text',
    ... slug='fav_drink')
    >>> Value.objects.create(entity=u, attribute=a, value_text='red bull')
    <Value: crazy_dev_user - Favorite Drink: "red bull">
    '''

    entity_ct = models.ForeignKey(ContentType, related_name='value_entities')
    entity_id = models.IntegerField()
    entity = generic.GenericForeignKey(ct_field='entity_ct',
                                       fk_field='entity_id')

    value_text = models.TextField(blank=True, null=True)
    value_float = models.FloatField(blank=True, null=True)
    value_int = models.IntegerField(blank=True, null=True)
    value_date = models.DateTimeField(blank=True, null=True)
    value_bool = models.NullBooleanField(blank=True, null=True)
    value_enum = models.ForeignKey(EnumValue, blank=True, null=True,
                                   related_name='eav_values')

    generic_value_id = models.IntegerField(blank=True, null=True)
    generic_value_ct = models.ForeignKey(ContentType, blank=True, null=True,
                                         related_name='value_values')
    value_object = generic.GenericForeignKey(ct_field='generic_value_ct',
                                             fk_field='generic_value_id')

    created = models.DateTimeField(_(u"created"), default=datetime.now)
    modified = models.DateTimeField(_(u"modified"), auto_now=True)

    attribute = models.ForeignKey(Attribute, db_index=True,
                                  verbose_name=_(u"attribute"))

    def save(self, *args, **kwargs):
        '''
        Validate and save this value
        '''
        self.full_clean()
        super(Value, self).save(*args, **kwargs)

    def clean(self):
        '''
        Raises ``ValidationError`` if this value's attribute is *TYPE_ENUM*
        and value_enum is not a valid choice for this value's attribute.
        '''
        if self.attribute.datatype == Attribute.TYPE_ENUM and \
           self.value_enum:
            if self.value_enum not in self.attribute.enum_group.enums.all():
                raise ValidationError(_(u"%(choice)s is not a valid " \
                                        u"choice for %s(attribute)") % \
                                        {'choice': self.value_enum,
                                         'attribute': self.attribute})

    def _get_value(self):
        '''
        Return the python object this value is holding
        '''
        return getattr(self, 'value_%s' % self.attribute.datatype)

    def _set_value(self, new_value):
        '''
        Set the object this value is holding
        '''
        setattr(self, 'value_%s' % self.attribute.datatype, new_value)

    value = property(_get_value, _set_value)

    def __unicode__(self):
        return u"%s - %s: \"%s\"" % (self.entity, self.attribute.name,
                                     self.value)
Ejemplo n.º 15
0
class XaploadImageRel(models.Model):
    image = models.ImageField(upload_to='media/')
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveSmallIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')
Ejemplo n.º 16
0
 class Model(models.Model):
     rel = generic.GenericRelation('Model')
     content_type = models.ForeignKey(ContentType)
     object_id = models.PositiveIntegerField()
     content_object = generic.GenericForeignKey('content_type',
                                                'object_id')
Ejemplo n.º 17
0
class Feature(models.Model):
    """Model used for representing user-generated features

        ======================  ==============================================
        Attribute               Description
        ======================  ==============================================
        ``user``                Creator

        ``name``                Name of the object
                                
        ``date_created``        When it was created

        ``date_modified``       When it was last updated.
        ======================  ==============================================
    """
    user = models.ForeignKey(User,
                             related_name="%(app_label)s_%(class)s_related")
    name = models.CharField(verbose_name="Name", max_length="255")
    date_created = models.DateTimeField(auto_now_add=True,
                                        verbose_name="Date Created")
    date_modified = models.DateTimeField(auto_now=True,
                                         verbose_name="Date Modified")
    sharing_groups = models.ManyToManyField(
        Group,
        editable=False,
        blank=True,
        null=True,
        verbose_name="Share with the following groups",
        related_name="%(app_label)s_%(class)s_related")
    content_type = models.ForeignKey(
        ContentType,
        blank=True,
        null=True,
        related_name="%(app_label)s_%(class)s_related")
    object_id = models.PositiveIntegerField(blank=True, null=True)
    collection = generic.GenericForeignKey('content_type', 'object_id')

    objects = ShareableGeoManager()

    def __unicode__(self):
        return u"%s_%s" % (self.model_uid(), self.pk)

    def __repr__(self):
        return u"%s_%s" % (self.model_uid(), self.pk)

    class Meta:
        abstract = True

    '''
    Note on keyword args rerun and form: These are extracted from kwargs so that they will not cause an unexpected 
    keyword argument error during call to super.save.  (They are used in the Analysis model save method, but become 
    superfluous here.)
    '''

    def save(self, rerun=True, form=None, *args, **kwargs):
        super(Feature, self).save(*args,
                                  **kwargs)  # Call the "real" save() method
        if form is not None:
            form.save_m2m()

    @models.permalink
    def get_absolute_url(self):
        return ('%s_resource' % (self.get_options().slug, ), (), {
            'uid': self.uid
        })

    @classmethod
    def get_options(klass):
        """
        Returns model class Options object
        """
        return get_model_options(klass.__name__)

    @classmethod
    def css(klass):
        """
        Specifies the CSS for representing features in kmltree, specifically the icon
        Works one of two ways:
        1. Use the icon_url Option and this default css() classmethod 
        2. Override the css() classmethod for more complex cases
        """
        url = klass.get_options().icon_url
        if url:
            if not url.startswith("/") and not url.startswith("http://"):
                url = settings.MEDIA_URL + url
            return """ li.%s > .icon { 
            background: url("%s") no-repeat scroll 0 0 transparent ! important; 
            display:inline ! important;
            } 

            div.%s > .goog-menuitem-content {
                background: url("%s") no-repeat scroll 0 0 transparent !important;
                display: block !important;
                padding-left: 22px;
                position: relative;
                left: -22px;
                height: 16px;
            } """ % (klass.model_uid(), url, klass.model_uid(), url)

    @property
    def options(self):
        return get_model_options(self.__class__.__name__)

    @classmethod
    def model_uid(klass):
        """
        class method providing the uid for the model class.
        """
        ct = ContentType.objects.get_for_model(klass)
        return "%s_%s" % (ct.app_label, ct.model)

    @property
    def hash(self):
        """
        For caching. This string represents a hash of all 
        attributes that may influence reporting results. 
        i.e. if this property changes, reports for the feature get rerun. 
        """
        important = "%s%s" % (self.date_modified, self.uid)
        return important.__hash__()

    @property
    def uid(self):
        """
        Unique identifier for this feature.
        """
        if not self.pk:
            raise Exception(
                'Trying to get uid for feature class that is not yet saved!')
        return "%s_%s" % (
            self.model_uid(),
            self.pk,
        )

    @property
    def kml_safe(self):
        """
        A safety valve for kmlapp...
        If one feature's .kml  property fails, 
        it won't bring down the entire request.
        This property is never to be overridden!
        """
        try:
            return self.kml
        except Exception as e:
            try:
                logger.error("%s .kml property is failing: \n%s\n" %
                             (self.uid, e.message))
            except:
                # just in case logging or the uid property are fubar
                print ".kml is failing on something"
            # Create a fallback KML placemark so it doesn't just disappear
            return """
            <Placemark id="%s">
                <visibility>0</visibility>
                <name>%s (KML Error)</name>
                <description>Error Details ... %s ... If the problem persists, please contact us.</description>
            </Placemark>
            """ % (self.uid, self.name, e.message)

    def add_to_collection(self, collection):
        """
        Add feature to specified FeatureCollection
        """
        assert issubclass(collection.__class__, FeatureCollection)
        assert self.__class__ in collection.get_options().get_valid_children()
        assert self.user == collection.user
        self.collection = collection
        self.save(rerun=False)

    def remove_from_collection(self):
        """
        Remove feature from FeatureCollection
        """
        collection = self.collection
        self.collection = None
        self.save(rerun=False)
        if collection:
            collection.save(rerun=True)

    def share_with(self, groups, append=False):
        """
        Share this feature with the specified group/groups.
        Owner must be a member of the group/groups.
        Group must have 'can_share' permissions else an Exception is raised
        """
        if not append:
            # Don't append to existing groups; Wipe the slate clean
            # Note that this is the default behavior
            self.sharing_groups.clear()

        if groups is None or groups == []:
            # Nothing to do here
            return True

        if isinstance(groups, Group):
            # Only a single group was provided, make a 1-item list
            groups = [groups]

        for group in groups:
            assert isinstance(group, Group)
            # Check that the group to be shared with has appropos permissions
            assert group in self.user.groups.all()
            try:
                gp = group.permissions.get(codename='can_share_features')
            except:
                raise Exception("The group you are trying to share with "
                                "does not have can_share permission")

            self.sharing_groups.add(group)

        self.save(rerun=False)
        return True

    def is_viewable(self, user):
        """ 
        Is this feauture viewable by the specified user? 
        Either needs to own it or have it shared with them.
        returns : Viewable(boolean), HttpResponse
        """
        # First, is the user logged in?
        if user.is_anonymous() or not user.is_authenticated():
            try:
                obj = self.__class__.objects.shared_with_user(user).get(
                    pk=self.pk)
                return True, HttpResponse(
                    "Object shared with public, viewable by anonymous user",
                    status=202)
            except self.__class__.DoesNotExist:
                # Unless the object is publicly shared, we won't give away anything
                return False, HttpResponse('You must be logged in', status=401)

        # Does the user own it?
        if self.user == user:
            return True, HttpResponse("Object owned by user", status=202)

        # Next see if its shared with the user
        try:
            # Instead having the sharing logic here, use the shared_with_user
            # We need it to return querysets so no sense repeating that logic
            obj = self.__class__.objects.shared_with_user(user).get(pk=self.pk)
            return True, HttpResponse("Object shared with user", status=202)
        except self.__class__.DoesNotExist:
            return False, HttpResponse("Access denied", status=403)

        return False, HttpResponse("Server Error in feature.is_viewable()",
                                   status=500)

    def copy(self, user=None):
        """
        Returns a copy of this feature, setting the user to the specified 
        owner. Copies many-to-many relations
        """
        # Took this code almost verbatim from the mpa model code.
        # TODO: Test if this method is robust, and evaluate alternatives like
        # that described in django ticket 4027
        # http://code.djangoproject.com/ticket/4027
        the_feature = self

        # Make an inventory of all many-to-many fields in the original feature
        m2m = {}
        for f in the_feature._meta.many_to_many:
            m2m[f.name] = the_feature.__getattribute__(f.name).all()

        # The black magic voodoo way,
        # makes a copy but relies on this strange implementation detail of
        # setting the pk & id to null
        # An alternate, more explicit way, can be seen at:
        # http://blog.elsdoerfer.name/2008/09/09/making-a-copy-of-a-model-instance
        the_feature.pk = None
        the_feature.id = None
        the_feature.save(rerun=False)

        the_feature.name = the_feature.name + " (copy)"

        # Restore the many-to-many fields
        for fname in m2m.keys():
            for obj in m2m[fname]:
                the_feature.__getattribute__(fname).add(obj)

        # Reassign User
        the_feature.user = user

        # Clear everything else
        the_feature.sharing_groups.clear()
        the_feature.remove_from_collection()

        the_feature.save(rerun=False)
        return the_feature
Ejemplo n.º 18
0
 class TaggedItem(models.Model):
     # no content_type field
     object_id = models.PositiveIntegerField()
     content_object = generic.GenericForeignKey()
Ejemplo n.º 19
0
class DummyGenericForeignKeyModel(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')
Ejemplo n.º 20
0
 class TaggedItem(models.Model):
     content_type = models.ForeignKey(ContentType)
     # missing object_id field
     content_object = generic.GenericForeignKey()
Ejemplo n.º 21
0
class Entry(models.Model):
    """
    Entry model for the logger app.
    
    This is a model that creates a generic relationship between it and
    other models for creating a "recent activity" history. It requires a global list variable in 
    the settings file named `LOGGER_MODELS`, with each value in the list being 
    in the format of `appname.model`.
    
    For example, if I have an app called `blog` and a model called `Post`
    that I want to include in my tumblelog, I would add this to my settings file.
    
    `LOGGER_MODELS = ['blog.post']`
    
    This model tries three methods for displaying the title, description,
    and title and description together on the site and in the RSS feed, and
    these methods are called `title`, `description` and `render`.
    
    It is done this way because of the way RSS displays the "title" and "description"
    separately.  If we only did a render, the RSS description of the entry
    would include both the title and the description, which would be
    undesired.
    
    There are three ways of usings these functions.
    
    1. Write a custom method in your model.
       It looks for this first, and if it doesn't find it, it moves on. It looks for 
       a method called `get_title` when getting the title, `get_description` for 
       showing the description, and `render` for displaying both the title and
       description.
       
       For example, if I have a blog app with a `Post` model, I can create a 
       `get_title`, `get_description`, and/or `render` method in my model and this 
       model will call it.
    
    2. Use a custom template.
       Inside of one of your template directories, you should have a folder for your
       app that is the name of your app.  Inside of this directory,
       create a file for the `title`, `description`, and
       `render` methods to use.  These should be named `<model_name>_title.html`, 
       `<model_name>_description.html`, and `<model_name>_render.html` respectively.
       
       For example, if I have created a blog app with a `Post` model, and I want
       to create a custom template for displaying the description, I would create
       a file `logger/post_description.html`.
       
       For the `render` method, you can use the `<model_name>_render.html`, or you
       can create a generic render template to be use by default.  Name it `render.html` 
       and put it in a folder called `logger` somewhere on your template path, 
       which will be `logger/render.html`.
       
    3. Use the default.
       This model will create generic title and description values.  If nothing
       is set for the title or description (either with a custom template or custom method),
       it will use the string representation of that object.
       
       Note: refer to the the second option above to see about creating a default
       template for the `render` method.
    """
    action = models.ForeignKey(Action, blank=True, null=True)
    created_at = models.DateTimeField()
    content_type = models.ForeignKey(ContentType, related_name='kate_logentry')
    object_id = models.PositiveIntegerField()
    public = models.BooleanField(default=True)

    content_object = generic.GenericForeignKey()

    objects = EntryManager()

    class Meta:
        ordering = ["-created_at"]
        verbose_name_plural = 'Log Entries'
        get_latest_by = 'created_at'

    # These methods below are for displaying the entry, both on the
    # site and in the RSS feeds.  Since the RSS feeds require that
    # we display the Title and Description of an item separately,
    # we have to have separate methods for them.  We also have a
    # render method that will display a custom render template or
    # use get_title and get_description to display one.

    def _get_title(self):
        """
        Here we get the title of the `Entry`. First, check for a 
        `get_title` method, then try to use a template called
        `<app_label>/<model_name>_title.html`.  If it finds neither, it
        will use the object's string representation.
        """
        # First, see if there is a title method on the content object
        if hasattr(self.content_object, 'get_title'):
            return self.content_object.get_title()

        # Next, see if there is template called <app_label>/<model_name>_title.html
        try:
            return render_to_string(
                "%s/%s_title.html" %
                (self.content_type.app_label, self.content_type.name),
                {'obj': self.content_object})
        except TemplateDoesNotExist:
            # Finally, just use the string representation of the object
            t = Template('{{ obj }}')
            c = Context({'obj': self.content_object})
            return t.render(c)

    title = property(_get_title)

    def _get_description(self):
        """
        Here we get the description of the `Entry`. First, check for a 
        `get_title` method, then try to use a template called
        `<app_label>/<model_name>_title.html`.  If it finds neither, it
        will use the object's string representation.
        """
        # First, see if there is a description method on the content object
        if hasattr(self.content_object, 'get_description'):
            return self.content_object.get_description()

        # Next, see if there is template called <app_label>/<model_name>_description.html
        try:
            return render_to_string(
                "%s/%s_description.html" %
                (self.content_type.app_label, self.content_type.name),
                {'obj': self.content_object})
        except TemplateDoesNotExist:
            # Finally, just use the string representation of the object
            t = Template('{{ obj }}')
            c = Context({'obj': self.content_object})
            return t.render(c)

    description = property(_get_description)

    def render(self):
        """
        This first looks for a render file under `<app_label>/<model_name>_title.html`
        and tries to use that to display this model.  If that template does
        not exist, it looks for a template called `djumblelog/render.html`, which exists
        in this app but can be replaced within another template directory.
        """
        # First, see if there is a render method on the content object
        if hasattr(self.content_object, 'render'):
            return self.content_object.render()

        # Next, see if there is a template called <app_label>/<model_name>_render.html
        try:
            return render_to_string(
                "%s/%s_render.html" %
                (self.content_type.app_label, self.content_type.name), {
                    'obj': self.content_object,
                    'title': self.title,
                    'description': self.description
                })
        except TemplateDoesNotExist:
            # Finally, we use our default `render.html` template to display the entry
            return render_to_string(
                "djumblelog/render.html", {
                    'obj': self.content_object,
                    'title': self.title,
                    'description': self.description
                })

    def get_absolute_url(self):
        """Use the `get_absolute_url` of the content object for our `Entry`"""
        return self.content_object.get_absolute_url()

    def save(self, *args, **kwargs):
        if not self.id:
            self.created_at = datetime.now()
        super(Entry, self).save(*args, **kwargs)

    def __unicode__(self):
        return u"%s: %s" % (self.content_type.model_class().__name__,
                            self.content_object)
Ejemplo n.º 22
0
 class TaggedItem(models.Model):
     content_type = models.ForeignKey(ContentType)
     object_id = models.PositiveIntegerField()
     content_object = generic.GenericForeignKey()
Ejemplo n.º 23
0
class Order(models.Model):
    """
    An order is created when products have been sold.

    **Attributes:**

    number
        The unique order number of the order, which is the reference for the
        customer.

    voucher_number, voucher_value, voucher_tax
        Storing this information here assures that we have it all time, even
        when the involved voucher will be deleted.

    requested_delivery_date
        A buyer requested delivery date (e.g. for a florist to deliver flowers
        on a specific date)

    pay_link
        A link to re-pay the order (e.g. for PayPal)

    invoice_address_id
        The invoice address of the order (this is not a FK because of circular
        imports).

    shipping_address_id
        The shipping address of the order (this is not a FK because of circular
        imports).

    """
    number = models.CharField(max_length=30)
    user = models.ForeignKey(User, verbose_name=_(u"User"), blank=True, null=True)
    session = models.CharField(_(u"Session"), blank=True, max_length=100)

    created = models.DateTimeField(_(u"Created"), auto_now_add=True)

    state = models.PositiveSmallIntegerField(_(u"State"), choices=ORDER_STATES, default=SUBMITTED)
    state_modified = models.DateTimeField(_(u"State modified"), auto_now_add=True)

    price = models.FloatField(_(u"Price"), default=0.0)
    tax = models.FloatField(_(u"Tax"), default=0.0)

    customer_firstname = models.CharField(_(u"firstname"), max_length=50)
    customer_lastname = models.CharField(_(u"lastname"), max_length=50)
    customer_email = models.CharField(_(u"email"), max_length=75)

    sa_content_type = models.ForeignKey(ContentType, related_name="order_shipping_address")
    sa_object_id = models.PositiveIntegerField()
    shipping_address = generic.GenericForeignKey('sa_content_type', 'sa_object_id')

    ia_content_type = models.ForeignKey(ContentType, related_name="order_invoice_address")
    ia_object_id = models.PositiveIntegerField()
    invoice_address = generic.GenericForeignKey('ia_content_type', 'ia_object_id')

    shipping_method = models.ForeignKey(ShippingMethod, verbose_name=_(u"Shipping Method"), blank=True, null=True)
    shipping_price = models.FloatField(_(u"Shipping Price"), default=0.0)
    shipping_tax = models.FloatField(_(u"Shipping Tax"), default=0.0)

    payment_method = models.ForeignKey(PaymentMethod, verbose_name=_(u"Payment Method"), blank=True, null=True)
    payment_price = models.FloatField(_(u"Payment Price"), default=0.0)
    payment_tax = models.FloatField(_(u"Payment Tax"), default=0.0)

    account_number = models.CharField(_(u"Account number"), blank=True, max_length=30)
    bank_identification_code = models.CharField(_(u"Bank identication code"), blank=True, max_length=30)
    bank_name = models.CharField(_(u"Bank name"), blank=True, max_length=100)
    depositor = models.CharField(_(u"Depositor"), blank=True, max_length=100)

    voucher_number = models.CharField(_(u"Voucher number"), blank=True, max_length=100)
    voucher_price = models.FloatField(_(u"Voucher value"), default=0.0)
    voucher_tax = models.FloatField(_(u"Voucher tax"), default=0.0)

    message = models.TextField(_(u"Message"), blank=True)
    pay_link = models.TextField(_(u"pay_link"), blank=True)

    uuid = models.CharField(max_length=50, editable=False, unique=True, default=get_unique_id_str)
    requested_delivery_date = models.DateTimeField(_(u"Delivery Date"), null=True, blank=True)

    class Meta:
        ordering = ("-created", )

    def __unicode__(self):
        return "%s (%s %s)" % (self.created.strftime("%x %X"), self.customer_firstname, self.customer_lastname)

    def get_pay_link(self, request):
        """
        Returns a pay link for the selected payment method.
        """
        if self.payment_method.module:
            payment_class = lfs.core.utils.import_symbol(self.payment_method.module)
            payment_instance = payment_class(request=request, order=self)
            try:
                return payment_instance.get_pay_link()
            except AttributeError:
                return ""
        else:
            return ""

    def can_be_paid(self):
        return self.state in (SUBMITTED, PAYMENT_FAILED, PAYMENT_FLAGGED)

    def get_name(self):
        order_name = ""
        for order_item in self.items.all():
            if order_item.product is not None:
                order_name = order_name + order_item.product.get_name() + ", "

        order_name.strip(', ')
        return order_name
Ejemplo n.º 24
0
class CI(TimeTrackable):
    uid = models.CharField(
        max_length=100,
        unique=True,
        verbose_name=_("CI UID"),
        null=True,
        blank=True,
    )
    # not required, since auto-save
    name = models.CharField(max_length=256, verbose_name=_("CI name"))
    business_service = models.BooleanField(
        verbose_name=_("Business service"),
        default=False,
    )
    technical_service = models.BooleanField(
        verbose_name=_("Technical service"),
        default=True,
    )
    pci_scope = models.BooleanField(default=False)
    layers = models.ManyToManyField(
        CILayer, verbose_name=_("layers containing given CI"))
    barcode = models.CharField(
        verbose_name=_("barcode"),
        max_length=255,
        unique=True,
        null=True,
        default=None,
    )
    content_type = models.ForeignKey(
        ContentType,
        verbose_name=_("content type"),
        null=True,
        blank=True,
    )
    object_id = models.PositiveIntegerField(
        verbose_name=_("object id"),
        null=True,
        blank=True,
    )
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    state = models.IntegerField(
        max_length=11,
        choices=CI_STATE_TYPES(),
        default=CI_STATE_TYPES.INACTIVE.id,
        verbose_name=_("state"),
    )
    status = models.IntegerField(
        max_length=11,
        choices=CI_STATUS_TYPES(),
        default=CI_STATUS_TYPES.REFERENCE.id,
        verbose_name=_("status"),
    )
    type = models.ForeignKey(CIType)
    zabbix_id = models.CharField(
        null=True,
        blank=True,
        max_length=30,
    )
    relations = models.ManyToManyField("self",
                                       symmetrical=False,
                                       through='CIRelation')
    added_manually = models.BooleanField(default=False)
    owners = models.ManyToManyField(
        'CIOwner',
        through='CIOwnership',
        verbose_name=_("configuration item owners"),
    )

    @property
    def url(self):
        return '/cmdb/ci/view/{0}'.format(self.id)

    @classmethod
    def get_duplicate_names(cls):
        dupes = cls.objects.values('name').distinct().annotate(
            models.Count('id'), ).filter(id__count__gt=1)
        cis = cls.objects.filter(name__in=[dupe['name'] for dupe in dupes
                                           ], ).order_by('name')
        # If I try to return the groupby itself the groups are empty
        for name, cis in it.groupby(cis, lambda x: x.name):
            yield name, list(cis)

    class Meta:
        unique_together = ('content_type', 'object_id')

    def __unicode__(self):
        return "%s (%s)" % (self.name, self.type)

    @classmethod
    def get_uid_by_content_object(cls, obj):
        prefix = CIContentTypePrefix.get_prefix_by_object(obj, '')
        return '%s-%s' % (prefix, obj.id)

    def get_jira_display(self):
        return "%(name)s %(uid)s - #%(barcode)s type: %(type)s" % (dict(
            name=self.name,
            uid=self.uid,
            barcode=self.barcode or '',
            type=self.type))

    def get_service(self):
        """
        Business / Organisation Unit Layer
            Venture 1->
                Venture 2->
                    Venture Role ->
                        Host ->
        Iterate upside, stop on first Venture in Business Layer
        """

    def get_technical_owners(self):
        if self.content_object and getattr(self.content_object, 'venture',
                                           None):
            return list([
                unicode(x)
                for x in self.content_object.venture.technical_owners()
            ] or ['-'])
        elif self.content_object and self.type.id == CI_TYPES.VENTURE.id:
            return list(
                [unicode(x) for x in self.content_object.technical_owners()]
                or ['-'])
        else:
            return ['-']

    @classmethod
    def get_cycle(cls):
        allci = CI.objects.all().values('pk')
        relations = CIRelation.objects.all().values('parent_id', 'child_id')
        cis = [x['pk'] for x in allci]
        rel = [(x['parent_id'], x['child_id']) for x in relations]
        cycle = cls.has_cycle(cis, rel)
        return cycle

    @classmethod
    def has_cycle(cls, nodes, edges):
        gr = digraph()
        gr.add_nodes(nodes)
        for edge in edges:
            gr.add_edge(edge)
        return find_cycle(gr)

    @classmethod
    def get_by_content_object(self, content_object):
        # find CI using his content object
        prefix = CIContentTypePrefix.get_prefix_by_object(content_object, None)
        if not prefix:
            # fixtures not loaded, or content type not registered in CMDB.
            # Skip checking.
            return None
        try:
            ci = CI.objects.get(uid='%s-%s' % (prefix, content_object.id))
        except CI.DoesNotExist:
            ci = None
        return ci

    @models.permalink
    def get_absolute_url(self):
        return "/cmdb/ci/view/%i" % self.id

    def save(self, user=None, *args, **kwargs):
        self.saving_user = user
        return super(CI, self).save(*args, **kwargs)

    def _get_related(self, self_field, other_field):
        """Iterate over the related objects.
        :param first_field: The field on relation that points to this CI
        :param second_field: The field on relation that points to other CI
        """
        for relation in getattr(self, self_field).all():
            yield getattr(relation, other_field)

    def get_parents(self):
        return self._get_related(self_field='child', other_field='parent')

    def get_children(self):
        return self._get_related(self_field='parent', other_field='child')