Beispiel #1
0
class Company(models.Model):

    done = [('Yes', 'Yes'), ('No', 'No')]

    job_type = [
        ('Full Time', 'Full Time'),
        ('Intern', 'Internship'),
        ('Others', 'Others'),
    ]

    user = models.OneToOneField(User, on_delete=models.CASCADE)
    company_name = models.CharField(
        max_length=30,
        blank=False,
        help_text='*Please type full name of your company')
    est_year = models.CharField(max_length=4,
                                blank=False,
                                help_text="*optional")
    hr_name = models.CharField(max_length=30,
                               blank=False,
                               help_text='*required')
    hr_phn = models.CharField(
        max_length=10,
        validators=[MinLengthValidator(10),
                    MaxLengthValidator(10)],
        blank=False,
        help_text='*required')
    headquarters = models.CharField(max_length=30,
                                    blank=False,
                                    help_text='*optional')
    about = models.TextField(max_length=1000,
                             blank=False,
                             help_text='*optional')
    job_type = models.CharField(max_length=100, blank=False, choices=job_type)
    designation = models.CharField(max_length=100,
                                   blank=False,
                                   help_text='*required')
    min_10_percent = models.FloatField(
        help_text='*In percent',
        validators=[MinValueValidator(0),
                    MaxValueValidator(100)],
        blank=False)
    min_12_percent = models.FloatField(
        help_text='*In percent',
        validators=[MinValueValidator(0),
                    MaxValueValidator(100)],
        blank=False)
    min_btech_cgpa = models.FloatField(
        validators=[MinValueValidator(0),
                    MaxValueValidator(10)], blank=False)
    information_technology = models.CharField(blank=False,
                                              choices=done,
                                              max_length=10)
    mechanical = models.CharField(blank=False, choices=done, max_length=10)
    cse = models.CharField(blank=False, choices=done, max_length=10)
    ee = models.CharField(blank=False, choices=done, max_length=10)
    ece = models.CharField(blank=False, choices=done, max_length=10)
    civil = models.CharField(blank=False, choices=done, max_length=10)
    ctc = models.FloatField(blank=False, help_text='In Lakhs')
    bond_years = models.FloatField(blank=False, help_text='*required')
    bond_amount = models.FloatField(help_text='*In Lakhs', blank=False)
    no_of_backlogs = models.IntegerField(blank=False, default=0)
    last_date_to_apply = models.DateField(blank=True, null=True)

    #	email         = models.EmailField(max_length=254,blank=False, help_text='*required')

    def __str__(self):
        return self.company_name
Beispiel #2
0
class Shop(models.Model):
    segment = models.ForeignKey(Segment, default=None, null=True, blank=True)
    admin_user = models.ForeignKey(User)
    title = models.CharField(_(u"שם החנות"), max_length=200)
    currency_name = models.CharField(_(u"שם המטבע"),
                                     default='MemeCache',
                                     max_length=200)
    description = models.TextField(_(u"תאור"),
                                   blank=True,
                                   null=True,
                                   validators=[MaxLengthValidator(MAX_TEXT)])

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __unicode__(self):
        return "id {}:{}".format(self.id, self.title)

    def get_absolute_url(self):
        return (reverse('memecache:shop_details', kwargs={'pk': str(self.id)}))

    def can_user_enter(self, user):
        if user.userprofile.get_segment() != self.segment:
            return False
        return True

    def get_cart(
            self,
            user,
            max_cart_inactivity_duration_seconds=MAX_CART_ACTIVITY_SECONDS):
        if self.can_user_enter(user):
            self.empty_unused_carts(max_cart_inactivity_duration_seconds)
            return self.cart_set.get_or_create(shop=self, customer=user)[0]
        return None

    def empty_unused_carts(
            self,
            max_cart_inactivity_duration_seconds=MAX_CART_ACTIVITY_SECONDS):
        now = timezone.now()
        oldest_active_cart_allowed = now - timedelta(
            seconds=max_cart_inactivity_duration_seconds)

        used_carts = self.cart_set.all().exclude(total_price=0)
        for cart in used_carts:
            if cart.updated_at < oldest_active_cart_allowed:
                cart.remove_all_items()
                self.delete_cart(cart)

    def delete_cart(self, cart):
        for product in self.product_set.all():
            cart.take_items(product, 0)
        cart.delete()

    def checkout(self, user):
        if not self.can_user_enter(user):
            return
        cart = self.get_cart(user)
        transaction_title = u'רכישה בחנות ' + self.title
        transaction = user.account.withdraw_and_return_transaction_if_ok(
            title=transaction_title,
            positive_item_price=cart.total_price,
            number_of_items=1,
            url=self.get_absolute_url())
        if transaction:
            purchase = Purchase(transaction=transaction,
                                total_price=cart.total_price)
            purchase.save()
            for product_selection in cart.productselection_set.all():
                number_of_selected_items = product_selection.number_of_selected_items
                for item_index in range(number_of_selected_items):
                    item_voucher = ItemVoucher(
                        shop=self,
                        product=product_selection.product,
                        customer=user,
                        purchase=purchase,
                        price=product_selection.product.item_price,
                        used=False)
                    item_voucher.clean()
                    item_voucher.save()

                product_selection.product.bought_items(
                    product_selection.number_of_selected_items)

                product_selection.delete()

            cart.delete()

    def can_item_voucher_be_marked_as_used(self, item_voucher):
        return (self.can_user_enter(item_voucher.customer)
                and item_voucher.product.can_use()
                and item_voucher.used == False)

    def marked_item_voucher_as_used(self, item_voucher):
        if self.can_item_voucher_be_marked_as_used(item_voucher):
            item_voucher.used = True
            item_voucher.save()

    def print_content(self):

        print_string = 'shop name is ' + self.title

        print_string += 'admin name is ' + self.admin_user.username

        print_string = 'currency name is ' + self.currency_name

        if self.segment:
            print_string += 'segment is ' + self.segment.title

        print print_string, 'number of products:', self.product_set.count()

        for product in self.product_set.all():
            product.print_content()

        print 'carts'

        for cart in self.cart_set.all():
            cart.print_content()
def get_config_variables():
    """
    Generator which yields all config variables of this app.

    It has to be evaluated during app loading (see apps.py).
    """

    # General

    yield ConfigVariable(
        name="agenda_start_event_date_time",
        default_value=None,
        input_type="datetimepicker",
        label="Begin of event",
        help_text="Input format: DD.MM.YYYY HH:MM",
        weight=200,
        group="Agenda",
        hidden=True,
    )

    # Numbering

    yield ConfigVariable(
        name="agenda_enable_numbering",
        label="Enable numbering for agenda items",
        input_type="boolean",
        default_value=True,
        weight=205,
        group="Agenda",
        subgroup="Numbering",
    )

    yield ConfigVariable(
        name="agenda_number_prefix",
        default_value="",
        label="Numbering prefix for agenda items",
        help_text="This prefix will be set if you run the automatic agenda numbering.",
        weight=206,
        group="Agenda",
        subgroup="Numbering",
        validators=(MaxLengthValidator(20),),
    )

    yield ConfigVariable(
        name="agenda_numeral_system",
        default_value="arabic",
        input_type="choice",
        label="Numeral system for agenda items",
        choices=(
            {"value": "arabic", "display_name": "Arabic"},
            {"value": "roman", "display_name": "Roman"},
        ),
        weight=207,
        group="Agenda",
        subgroup="Numbering",
    )

    # Visibility

    yield ConfigVariable(
        name="agenda_item_creation",
        label="Add to agenda",
        default_value="default_yes",
        input_type="choice",
        choices=(
            {"value": "always", "display_name": "Always"},
            {"value": "never", "display_name": "Never"},
            {"value": "default_yes", "display_name": "Ask, default yes"},
            {"value": "default_no", "display_name": "Ask, default no"},
        ),
        weight=210,
        group="Agenda",
        subgroup="Visibility",
    )

    yield ConfigVariable(
        name="agenda_new_items_default_visibility",
        default_value="2",
        input_type="choice",
        choices=(
            {"value": "1", "display_name": "Public item"},
            {"value": "2", "display_name": "Internal item"},
            {"value": "3", "display_name": "Hidden item"},
        ),
        label="Default visibility for new agenda items (except topics)",
        weight=211,
        group="Agenda",
        subgroup="Visibility",
    )

    yield ConfigVariable(
        name="agenda_hide_internal_items_on_projector",
        default_value=True,
        input_type="boolean",
        label="Hide internal items when projecting subitems",
        weight=212,
        group="Agenda",
        subgroup="Visibility",
    )

    yield ConfigVariable(
        name="agenda_show_subtitle",
        default_value=True,
        input_type="boolean",
        label="Show motion submitters in the agenda",
        weight=213,
        group="Agenda",
        subgroup="Visibility",
    )

    # List of speakers

    yield ConfigVariable(
        name="agenda_show_last_speakers",
        default_value=0,
        input_type="integer",
        label="Number of last speakers to be shown on the projector",
        weight=220,
        group="Agenda",
        subgroup="List of speakers",
        validators=(MinValueValidator(0),),
    )

    yield ConfigVariable(
        name="agenda_show_next_speakers",
        default_value=-1,
        input_type="integer",
        label="Number of the next speakers to be shown on the projector",
        help_text="Enter number of the next shown speakers. Choose -1 to show all next speakers.",
        weight=222,
        group="Agenda",
        subgroup="List of speakers",
        validators=(MinValueValidator(-1),),
    )

    yield ConfigVariable(
        name="agenda_countdown_warning_time",
        default_value=0,
        input_type="integer",
        label="Show orange countdown in the last x seconds of speaking time",
        help_text="Enter duration in seconds. Choose 0 to disable warning color.",
        weight=224,
        group="Agenda",
        subgroup="List of speakers",
        validators=(MinValueValidator(0),),
    )

    yield ConfigVariable(
        name="projector_default_countdown",
        default_value=60,
        input_type="integer",
        label="Predefined seconds of new countdowns",
        weight=226,
        group="Agenda",
        subgroup="List of speakers",
    )

    yield ConfigVariable(
        name="agenda_couple_countdown_and_speakers",
        default_value=True,
        input_type="boolean",
        label="Couple countdown with the list of speakers",
        help_text="[Begin speech] starts the countdown, [End speech] stops the countdown.",
        weight=228,
        group="Agenda",
        subgroup="List of speakers",
    )

    yield ConfigVariable(
        name="agenda_enable_point_of_order_speakers",
        default_value=False,
        input_type="boolean",
        label="Enable points of order",
        weight=229,
        group="Agenda",
        subgroup="List of speakers",
    )

    yield ConfigVariable(
        name="agenda_list_of_speakers_speaker_note_for_everyone",
        default_value=False,
        input_type="boolean",
        label="Everyone can see the request of a point of order (instead of managers for list of speakers only)",
        weight=230,
        group="Agenda",
        subgroup="List of speakers",
    )

    yield ConfigVariable(
        name="agenda_hide_amount_of_speakers",
        default_value=False,
        input_type="boolean",
        label="Hide the amount of speakers in subtitle of list of speakers slide",
        weight=231,
        group="Agenda",
        subgroup="List of speakers",
    )

    yield ConfigVariable(
        name="agenda_present_speakers_only",
        default_value=False,
        input_type="boolean",
        label="Only present participants can be added to the list of speakers",
        weight=232,
        group="Agenda",
        subgroup="List of speakers",
    )

    yield ConfigVariable(
        name="agenda_show_first_contribution",
        default_value=False,
        input_type="boolean",
        label="Show hint »first speech« in the list of speakers management view",
        weight=234,
        group="Agenda",
        subgroup="List of speakers",
    )

    yield ConfigVariable(
        name="agenda_list_of_speakers_initially_closed",
        default_value=False,
        input_type="boolean",
        label="List of speakers is initially closed",
        weight=235,
        group="Agenda",
        subgroup="List of speakers",
    )

    yield ConfigVariable(
        name="agenda_list_of_speakers_enable_pro_contra_speech",
        default_value=False,
        input_type="boolean",
        label="Enable forspeech / counter speech",
        weight=240,
        group="Agenda",
        subgroup="List of speakers",
    )

    yield ConfigVariable(
        name="agenda_list_of_speakers_can_set_mark_self",
        default_value=False,
        input_type="boolean",
        label="Enable star icon to mark speaker (e.g. for contribution)",
        weight=245,
        group="Agenda",
        subgroup="List of speakers",
    )
Beispiel #4
0
class Entry(models.Model):

    title = models.CharField(max_length=255,
                             verbose_name=_(u'Entry title'),
                             unique=True)
    slug = models.SlugField(max_length=255,
                            unique=True,
                            verbose_name=_(u'Slug'))
    url = models.URLField(verbose_name=_(u'URL'), max_length=255)
    thumbnail = models.ImageField(
        verbose_name=_(u'Featured image'),
        blank=True,
        null=True,
        help_text=_(u"This will be used in our summary and list views."),
        upload_to=_upload_path('submission-entry'))
    created_by = models.ForeignKey(Profile, blank=True, null=True)
    video_url = models.URLField(verbose_name=_(u'Gameplay URL'),
                                max_length=255,
                                default="")
    description = models.TextField(verbose_name=_(u'Description'),
                                   validators=[MaxLengthValidator(1000)],
                                   default="")
    category = models.ForeignKey(Category,
                                 verbose_name=_(u'Category'),
                                 blank=True,
                                 null=True)
    team_name = models.CharField(max_length=255,
                                 verbose_name=_(u'Team name'),
                                 blank=True)
    team_members = models.TextField(verbose_name=_(u'Members'),
                                    validators=[MaxLengthValidator(250)],
                                    blank=True)
    team_description = models.TextField(verbose_name=_(u'Description'),
                                        validators=[MaxLengthValidator(250)],
                                        blank=True)
    to_market = models.BooleanField(verbose_name="redirect to marketplace",
                                    default=False)

    def __unicode__(self):
        return self.title

    def editable_by(self, user=AnonymousUser()):
        if not user.is_anonymous():
            if self.created_by == user.get_profile():
                return True

    def get_image_src(self):
        """
        If a thumbnail has been included this provides an easy way to grab it
        from the DB and display it (or a default) in the templates
        """
        media_url = getattr(settings, 'MEDIA_URL', '')
        static_url = getattr(settings, 'STATIC_URL', '')
        path = lambda f: f and '%s%s' % (media_url, f)
        static_path = lambda f: f and '%s%s' % (static_url, f)
        return path(
            self.thumbnail) or static_path('base/img/entry-default.gif')

    @property
    def has_entry_feature(self):
        """
        If a project has provided a URL of gameplay action we want to display
        that in the single view template as the feature, opposed to the
        screenshot (which could still be the default)
        Only if the video is from a site that supported oembed do we class it as]
        'featurable'
        """
        return url2embed(self.video_url) or self.thumbnail

    def get_entry_feature(self):
        """
        If there is a video_url we want to include that as a feature, otherwise
        we fall through to the thumbnail
        """

        video_embed = url2embed(self.video_url)

        if video_embed:
            return video_embed
        if self.thumbnail:
            return '<img src="%s" alt=""/>' % self.get_image_src()

    class Meta:
        verbose_name_plural = 'Entries'
Beispiel #5
0
class SignUpForm(UserCreationForm):
    """
    form that overrides Django's user creation form to include the requirement of student id
    """
    error_messages = {
        'student_id_taken': 'Student ID already has an account.',
        'password_mismatch': 'Passwords do not match.'
    }

    student_id = forms.CharField(help_text='Required. Format: xxxxxxxxx',
                                 validators=[
                                     MaxLengthValidator(limit_value=9),
                                     MinLengthValidator(limit_value=9), numeric
                                 ])

    def clean_student_id(self):
        """
        method to be called when cleaning form input within django's core functionalities
        verifies if student id is taken
        :return: student id number
        """
        student_id = self.data.get("student_id").strip()
        if Student.student_exists(student_id):
            raise ValidationError(self.error_messages['student_id_taken'], )
        return student_id

    def clean_username(self):
        username = self.cleaned_data['username']
        if len(username) < 8:
            raise ValidationError(user_error_messages['un_lt'], )

        if len(username) > 16:
            raise ValidationError(user_error_messages['un_gt'], )

        return username

    def clean_password1(self):
        pw = self.data['password1']

        if len(pw) < 8:
            raise ValidationError(user_error_messages['pw_lt'], )

        if len(pw) > 24:
            raise ValidationError(user_error_messages['pw_gt'], )

        if not hasUpper(pw):
            raise ValidationError(user_error_messages['pw_upper'], )

        if not hasLower(pw):
            raise ValidationError(user_error_messages['pw_lower'], )

        if not hasDigit(pw):
            raise ValidationError(user_error_messages['pw_digit'], )

        if not hasSpecialchar(pw):
            raise ValidationError(user_error_messages['pw_sc'], )
        return pw

    class Meta:
        model = User
        fields = (
            'username',
            'student_id',
            'password1',
            'password2',
        )
Beispiel #6
0
class Repair(models.Model):
    """
    Proxies service order data between our internal
    service orders and GSX repairs
    """
    order = models.ForeignKey(Order, editable=False, on_delete=models.PROTECT)
    device = models.ForeignKey(Device,
                               editable=False,
                               on_delete=models.PROTECT)
    parts = models.ManyToManyField(ServiceOrderItem, through=ServicePart)

    created_at = models.DateTimeField(auto_now_add=True, editable=False)
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL,
                                   editable=False,
                                   on_delete=models.PROTECT,
                                   related_name="created_repairs")

    tech_id = models.CharField(default='',
                               blank=True,
                               max_length=15,
                               verbose_name=_(u'Technician'))
    unit_received_at = models.DateTimeField(default=timezone.now,
                                            verbose_name=_(u'Unit Received'))
    submitted_at = models.DateTimeField(null=True, editable=False)
    completed_at = models.DateTimeField(null=True, editable=False)
    completed_by = models.ForeignKey(settings.AUTH_USER_MODEL,
                                     null=True,
                                     editable=False,
                                     on_delete=models.PROTECT,
                                     related_name="completed_repairs")
    request_review = models.BooleanField(
        default=False,
        help_text=_("Repair should be reviewed by Apple before confirmation"))
    confirmation = models.CharField(max_length=15, default='', editable=False)
    reference = models.CharField(blank=True,
                                 default='',
                                 max_length=16,
                                 verbose_name=_("Reference"))

    symptom = models.TextField()
    diagnosis = models.TextField()
    notes = models.TextField(
        blank=True,
        default='',
        validators=[MaxLengthValidator(800)],
        help_text=_("Notes are mandatory when requesting review."))
    #  user-friendly status description from GSX
    status = models.CharField(default='', editable=False, max_length=128)
    status_code = models.CharField(max_length=4,
                                   default='',
                                   editable=False,
                                   choices=gsxws.repairs.REPAIR_STATUSES)

    attachment = models.FileField(
        upload_to='repairs',
        null=True,
        blank=True,
        help_text=_(
            'Choose files to be sent with the repair creation request'))
    repair_number = models.CharField(default='', max_length=12, editable=False)
    mark_complete = models.BooleanField(
        blank=True,
        default=False,
        verbose_name=_("mark complete"),
        help_text=_("Requires replacement serial number"))
    replacement_sn = models.CharField(
        blank=True,
        default='',
        max_length=18,
        verbose_name=_("New serial number"),
        help_text=_("Serial Number of replacement part"))
    # the account through which this repair was submitted
    gsx_account = models.ForeignKey(GsxAccount,
                                    editable=False,
                                    on_delete=models.PROTECT)

    repair_type = models.CharField(max_length=2,
                                   default="CA",
                                   editable=False,
                                   choices=gsxws.REPAIR_TYPES)

    component_data = models.TextField(default='', editable=False)
    consumer_law = models.NullBooleanField(
        default=None,
        help_text=_('Repair is eligible for consumer law coverage'))
    acplus = models.NullBooleanField(
        default=None,
        verbose_name=_('AppleCare+'),
        help_text=_('Repair is covered by AppleCare+'))

    symptom_code = models.CharField(max_length=7, default='')
    issue_code = models.CharField(max_length=7, default='')
    objects = ActiveManager()

    def is_submitted(self):
        return self.submitted_at is not None

    def get_symptom_code_choices(self):
        """
        Returns the possible symptom codes for the current serial number
        """
        # @fixme: what if it's someone else ordering the part?
        self.gsx_account.connect(self.created_by)
        ckey = 'symptom_codes-%s' % self.device.sn
        si = SymptomIssue(serialNumber=self.device.sn)
        return cache_getset(ckey, si.fetch)

    def get_issue_code_choices(self):
        """
        Returns the possible issue codes for the current symptom code
        """
        # @fixme: what if it's someone else ordering the part?
        self.gsx_account.connect(self.created_by)
        ckey = 'issue_codes-%s' % self.symptom_code
        si = SymptomIssue(reportedSymptomCode=self.symptom_code)
        return cache_getset(ckey, si.fetch)

    @property
    def has_cl_parts(self):
        """
        Returns true if this repair contains Consumer Law parts
        """
        return self.servicepart_set.filter(coverage_status='VW').exists()

    @property
    def can_mark_complete(self):
        """
        Returns true if this repair can be marked complete after submitting
        """
        parts = self.servicepart_set.all()
        if len(parts) > 1: return False
        replacements = [p for p in parts if p.is_replacement()]
        return len(replacements) == 1

    @classmethod
    def create_from_gsx(cls, confirmation, order, device, user):
        """Creates a new Repair for order with confirmation number."""
        try:
            repair = cls.objects.get(confirmation=confirmation)
            msg = {'repair': repair.confirmation, 'order': repair.order}
            raise ValueError(
                _('Repair %(repair)s already exists for order %(order)s') %
                msg)
        except cls.DoesNotExist:
            pass

        repair = cls(order=order, created_by=user)
        repair.device = device
        repair.confirmation = confirmation
        repair.gsx_account = GsxAccount.default(user, order.queue)
        repair.submitted_at = timezone.now(
        )  # RepairDetails doesn't have this!
        repair.save()

        try:
            repair.get_details()
            repair.update_status(user)
        except gsxws.GsxError as e:
            if e.code == 'RPR.LKP.01':  # repair not found
                repair.delete()
                raise ValueError(
                    _('Repair %s not found in GSX') % confirmation)

        return repair

    def create_purchase_order(self):
        # Create local purchase order
        po = PurchaseOrder(supplier="Apple", created_by=self.created_by)
        po.location = self.created_by.get_location()
        po.reference = self.reference
        po.sales_order = self.order
        po.save()
        return po

    def warranty_status(self):
        """
        Gets warranty status for this device and these parts
        """
        self.connect_gsx(self.created_by)
        product = gsxws.Product(self.device.sn)
        parts = [(
            p.code,
            p.comptia_code,
        ) for p in self.order.get_parts()]
        return product.warranty(parts,
                                self.get_received_date(),
                                ship_to=self.gsx_account.ship_to)

    def is_open(self):
        return self.completed_at is None

    def get_products(self):
        """
        Returns the Service Order Items in this Repair
        """
        return [x.order_item for x in self.servicepart_set.all()]

    def get_number(self, user=None):
        return self.confirmation or _("New GSX Repair")

    def set_parts(self, parts):
        """
        Resets this Repair's part listing
        """
        ServicePart.objects.filter(repair=self).delete()
        for p in parts:
            part = ServicePart.from_soi(self, p)
            part.save()

    def add_part(self, order_item, user):
        """
        Adds this Order Item as a part to this GSX repair
        """
        self.connect_gsx(user)
        gsx_rep = self.get_gsx_repair()

        part = ServicePart.from_soi(self, order_item)
        order_line = part.get_repair_order_line()

        gsx_rep.update({'orderLines': [order_line]})
        part.order(user)

        return part

    def add_gsx_part(self, part):
        """
        Adds a part that has been added manually in GSX web UI
        """
        # part has been added to the order, but not the GSX repair
        try:
            oi = self.order.products.get(code=part.partNumber)
        except ServiceOrderItem.DoesNotExist:
            new_part = ServicePart(part_number=part.partNumber)
            try:
                p = Product.objects.get(code=part.partNumber)
            except Product.DoesNotExist:
                p = Product.from_gsx(new_part.lookup())
                p.save()

            oi = self.order.add_product(p, 1, self.created_by)

        oi.comptia_code = part.comptiaCode or ''
        oi.comptia_modifier = part.comptiaModifier or ''
        oi.save()

        sp = ServicePart.from_soi(self, oi)
        sp.set_part_details(part)

        sp.order(self.created_by)
        sp.save()

    def submit(self, customer_data):
        """
        Creates a new GSX repair and all the documentation that goes along with it
        """
        if len(self.parts.all()) < 1:
            raise ValueError(_("Please add some parts to the repair"))

        if not self.order.queue:
            raise ValueError(_("Order has not been assigned to a queue"))

        repair_data = self.to_gsx()

        if self.repair_type == "CA":
            gsx_repair = gsxws.CarryInRepair(**repair_data)
        if self.repair_type == "ON":
            gsx_repair = gsxws.IndirectOnsiteRepair(**repair_data)

        customer_data['regionCode'] = self.gsx_account.region
        gsx_repair.customerAddress = gsxws.Customer(**customer_data)

        if self.component_data:
            ccd = []
            cd = json.loads(self.component_data)
            for k, v in cd.items():
                ccd.append(gsxws.ComponentCheck(component=k, serialNumber=v))

            gsx_repair.componentCheckDetails = ccd

        parts = [p.get_repair_order_line() for p in self.servicepart_set.all()]
        gsx_repair.orderLines = parts

        # Submit the GSX repair request
        result = gsx_repair.create()

        po = self.create_purchase_order()

        for p in self.servicepart_set.all():
            p.purchase_order = po
            p.created_by = self.created_by
            p.save()

            poi = PurchaseOrderItem.from_soi(po, p.order_item, self.created_by)
            poi.save()

        confirmation = result.confirmationNumber
        self.confirmation = confirmation
        self.submitted_at = timezone.now()

        po.confirmation = confirmation
        po.submit(self.created_by)

        self.save()

        msg = _(u"GSX repair %s created") % confirmation
        self.order.notify("gsx_repair_created", msg, self.created_by)

        if repair_data.get("markCompleteFlag") is True:
            self.close(self.created_by)

    def get_gsx_repair(self):
        return gsxws.CarryInRepair(self.confirmation)

    def get_unit_received(self):
        """
        Returns (as a tuple) the GSX-compatible date and time of
        when this unit was received
        """
        import locale
        langs = gsxws.get_format('en_XXX')
        ts = self.unit_received_at
        loc = locale.getlocale()
        # reset locale to get correct AM/PM value
        locale.setlocale(locale.LC_TIME, None)
        result = ts.strftime(langs['df']), ts.strftime(langs['tf'])
        locale.setlocale(locale.LC_TIME, loc)
        return result

    def get_received_date(self):
        return self.get_unit_received()[0]

    def to_gsx(self):
        """
        Returns this Repair as a GSX-compatible dict
        """
        data = {'serialNumber': self.device.sn}
        data['notes'] = self.notes
        data['symptom'] = self.symptom
        data['poNumber'] = self.reference
        data['diagnosis'] = self.diagnosis
        data['shipTo'] = self.gsx_account.ship_to

        data['reportedSymptomCode'] = self.symptom_code
        data['reportedIssueCode'] = self.issue_code

        # checkIfOutOfWarrantyCoverage
        if self.tech_id:
            data['diagnosedByTechId'] = self.tech_id

        ts = self.get_unit_received()
        data['unitReceivedDate'] = ts[0]
        data['unitReceivedTime'] = ts[1]

        if self.attachment:
            data['fileData'] = self.attachment
            data['fileName'] = os.path.basename(self.attachment.name)

        if self.mark_complete:
            data['markCompleteFlag'] = self.mark_complete
            data['replacementSerialNumber'] = self.replacement_sn

        data['requestReviewByApple'] = self.request_review

        if self.consumer_law is not None:
            data['consumerLawEligible'] = self.consumer_law

        if self.acplus is not None:
            data['acPlusFlag'] = self.acplus

        return data

    def has_serialized_parts(self):
        """
        Checks if this Repair has any serialized parts
        """
        count = self.parts.filter(
            servicepart__order_item__product__is_serialized=True).count()
        return count > 0

    def check_components(self):
        """
        Runs GSX component check for this repair's parts
        """
        l = gsxws.Lookup(serialNumber=self.device.sn)
        l.repairStrategy = self.repair_type
        l.shipTo = self.gsx_account.ship_to
        parts = []

        for i in self.servicepart_set.all():
            part = gsxws.ServicePart(i.part_number)
            part.symptomCode = i.comptia_code
            parts.append(part)

        try:
            r = l.component_check(parts)
        except gsxws.GsxError as e:
            if e.code == "COMP.LKP.004":
                return  # Symptom Code not required for Replacement and Other category parts.
            raise e

        if r.componentDetails is None:
            return

        if len(self.component_data) < 1:
            d = {}
            for i in r.componentDetails:
                f = i.componentCode
                d[f] = i.componentDescription

            self.component_data = json.dumps(d)

        return self.component_data

    def connect_gsx(self, user=None):
        """
        Initialize the GSX session with the right credentials.
        User can also be different from the one who initially created the repair.
        """
        account = user or self.created_by
        return self.gsx_account.connect(account)

    def set_status_code(self, newstatus):
        self.status_code = newstatus
        rep = self.get_gsx_repair()
        rep.set_status(self.status_code)
        self.save()

    def set_status(self, new_status, user):
        """
        Sets the current status of this repair to new_status
        and notifies the corresponding Service Order
        """
        if not new_status == self.status:
            self.status = new_status
            self.save()
            self.order.notify("repair_status_changed", self.status, user)

    def get_status(self):
        """Return status description of this repair."""
        return self.status if len(self.status) else _('No status')

    def update_status(self, user):
        """Update status description from GSX"""
        repair = self.get_gsx_repair()
        status = repair.status().repairStatus
        self.set_status(status, user)

        return self.status

    def get_details(self):
        repair = self.get_gsx_repair()
        details = repair.details()

        if isinstance(details.partsInfo, dict):
            details.partsInfo = [details.partsInfo]

        self.update_details(details)
        return details

    def get_return_label(self, part):
        self.get_details()
        part = self.servicepart_set.get(pk=part)
        return part.get_return_label()

    def update_details(self, details):
        """
        Updates what local info we have about this particular GSX repair
        """
        part_list = list(self.servicepart_set.all().order_by('id'))

        for i, p in enumerate(details.partsInfo):
            try:
                part = part_list[i]
                part.set_part_details(p)
                part.save()
            except IndexError:  # part added in GSX web ui...
                self.add_gsx_part(p)
            except AttributeError:  # some missing attribute in set_part_details()
                pass

    def get_replacement_sn(self):
        """
        Try to guess replacement part's SN
        """
        oi = self.order.serviceorderitem_set.filter(
            product__is_serialized=True, product__part_type="REPLACEMENT")

        try:
            return oi[0].sn
        except IndexError:
            pass

    def get_sn_update_parts(self):
        """
        Returns parts eligible for SN update
        """
        return self.servicepart_set.exclude(return_code='GPR')

    def close(self, user):
        """
        Mark the GSX repair as complete
        """
        self.connect_gsx(user)
        repair = self.get_gsx_repair()

        try:
            # Update part serial numbers
            [part.update_sn() for part in self.get_sn_update_parts()]
            repair.mark_complete()
        except gsxws.GsxError as e:
            """
            Valid GSX errors are:
            'ACT.BIN.01': Repair # provided is not valid. Please enter a valid repair #.
            'RPR.LKP.01': No Repair found matching search criteria.
            'RPR.LKP.010': No Repair found matching the search criteria.
            'RPR.COM.030': Cannot mark repair as complete for Unit $1. Repair is not open.
            'RPR.COM.036': Repair for Unit $1 is already marked as complete.
            'RPR.COM.019': This repair cannot be updated.
            'RPR.LKP.16': This Repair Cannot be Updated.Repair is not Open.
            'RPR.COM.136': Repair $1 cannot be marked complete as the Warranty
            Claims Certification Form status is either Declined or Hold.
            'ENT.UPL.022': 'Confirmation # $1 does not exist.'
            """
            errorlist = (
                'ACT.BIN.01',
                'RPR.LKP.01',
                'RPR.LKP.010',
                'RPR.COM.030',
                'RPR.COM.036',
                'RPR.COM.019',
                'RPR.LKP.16',
                'RPR.COM.136',
                'ENT.UPL.022',
            )

            if e.code not in errorlist:
                raise e

        status = repair.status()
        self.set_status(status.repairStatus, user)
        self.complete(user)

    def complete(self, user):
        """
        Mark our local copy of this GSX repair as complete
        """
        self.completed_at = timezone.now()
        self.completed_by = user
        self.save()

        msg = _('GSX repair %s marked complete') % self.confirmation
        self.order.notify('gsx_repair_complete', msg, user)

        queue = self.order.queue
        if queue.status_repair_completed:
            status = queue.status_repair_completed
            self.order.set_status(status, user)

    def duplicate(self, user):
        """
        Makes a copy of this GSX Repair
        """
        new_rep = Repair(order=self.order, created_by=user, device=self.device)
        new_rep.repair_type = self.repair_type
        new_rep.tech_id = self.tech_id
        new_rep.symptom = self.symptom
        new_rep.diagnosis = self.diagnosis
        new_rep.notes = self.notes
        new_rep.reference = self.reference
        new_rep.request_review = self.request_review
        new_rep.mark_complete = self.mark_complete
        new_rep.unit_received_at = self.unit_received_at
        new_rep.attachment = self.attachment
        new_rep.gsx_account = self.gsx_account

        new_rep.save()
        new_rep.set_parts(self.order.get_parts())

        return new_rep

    def get_absolute_url(self):
        if self.submitted_at is None:
            url = 'repairs-edit_repair'
        else:
            url = 'repairs-view_repair'

        return reverse(url, args=[self.order.pk, self.pk])

    def __unicode__(self):
        if self.pk is not None:
            return _("Repair %d") % self.pk

    class Meta:
        app_label = "servo"
        get_latest_by = "created_at"
Beispiel #7
0
class BarcodeForm(forms.Form):
    error_messages = {'invalid': _(u"Expecting only numbers for barcodes")}
    validators = [
        MaxLengthValidator(255),
        MinLengthValidator(1),
        RegexValidator(regex=r'^[0-9]*$',
                       message=_(u"Expecting only numbers for barcodes"))
    ]

    barcode = forms.CharField(
        error_messages=error_messages,
        validators=validators,
        widget=forms.NumberInput(attrs=disable_copy_input),
        label=_(u"Barcode"))
    barcode_copy = forms.CharField(
        error_messages=error_messages,
        validators=validators,
        widget=forms.NumberInput(attrs=disable_copy_input),
        label=_(u"Barcode Copy"))

    tally_id = forms.IntegerField(widget=forms.HiddenInput())

    def __init__(self, *args, **kwargs):
        super(BarcodeForm, self).__init__(*args, **kwargs)
        self.fields['barcode'].widget.attrs['autofocus'] = 'on'

    def clean(self):
        """Verify that barcode and barcode copy match and that the barcode is
        for a result form in the system.

        Also checks if the center,station and/or races are enabled.
        """
        if self.is_valid():
            cleaned_data = super(BarcodeForm, self).clean()
            barcode = cleaned_data.get('barcode')
            barcode_copy = cleaned_data.get('barcode_copy')
            tally_id = cleaned_data.get('tally_id')

            if barcode != barcode_copy:
                raise forms.ValidationError(_(u"Barcodes do not match!"))

            try:
                result_form = ResultForm.objects.get(barcode=barcode,
                                                     tally__id=tally_id)
            except ResultForm.DoesNotExist:
                raise forms.ValidationError(_(u"Barcode does not exist."))
            else:
                if result_form.center and not result_form.center.active:
                    raise forms.ValidationError(_(u"Center is disabled."))
                elif result_form.station_number:
                    try:
                        station = Station.objects.get(
                            station_number=result_form.station_number,
                            center=result_form.center)
                    except Station.DoesNotExist:
                        raise forms.ValidationError(
                            _(u"Station does not exist."))
                    else:
                        if not station.active:
                            raise forms.ValidationError(
                                _(u"Station disabled."))
                        elif station.sub_constituency:
                            ballot = station.sub_constituency.get_ballot()
                            if ballot and not ballot.active:
                                raise forms.ValidationError(
                                    _(u"Race disabled."))

            return cleaned_data
Beispiel #8
0
from django_select2.forms import (
    Select2Widget as DS2_Select2Widget,
    Select2MultipleWidget as DS2_Select2MultipleWidget,
    ModelSelect2Widget as DS2_ModelSelect2Widget,
    ModelSelect2MultipleWidget as DS2_ModelSelect2MultipleWidget,
    Select2TagWidget as DS2_Select2TagWidget,
)
from django.core.validators import RegexValidator, MaxLengthValidator
from django.db import models
from django import forms
from django.utils.safestring import mark_safe


GHUSERNAME_MAX_LENGTH_VALIDATOR = MaxLengthValidator(39,
    message='Maximum allowed username length is 39 characters.',
)
# according to https://stackoverflow.com/q/30281026,
# GH username can only contain alphanumeric characters and
# hyphens (but not consecutive), cannot start or end with
# a hyphen, and can't be longer than 39 characters
GHUSERNAME_REGEX_VALIDATOR = RegexValidator(
    # regex inspired by above StackOverflow thread
    regex=r'^([a-zA-Z\d](?:-?[a-zA-Z\d])*)$',
    message='This is not a valid GitHub username.',
)


class NullableGithubUsernameField(models.CharField):
    def __init__(self, **kwargs):
        kwargs.setdefault('null', True)
        kwargs.setdefault('blank', True)
class Entidad(models.Model):
    BOOL_ACTIVO = ((True, 'Si'), (False, 'No'))
    nombre = models.CharField(max_length=255,
                              validators=[
                                  MinLengthValidator(1),
                                  MaxLengthValidator(255),
                              ],
                              unique=True,
                              db_index=True,
                              help_text='Escribir el nombre de la entidad.')
    slogan = models.CharField(blank=True,
                              null=True,
                              max_length=255,
                              db_index=True,
                              help_text='Escribir el slogan de la entidad.')
    siglas = models.CharField(
        max_length=10,
        validators=[
            MinLengthValidator(1),
            MaxLengthValidator(10),
        ],
        db_index=True,
    )
    ruc = models.CharField(verbose_name='R.U.C.',
                           unique=True,
                           max_length=20,
                           validators=[
                               MinLengthValidator(1),
                               MaxLengthValidator(20),
                           ],
                           db_index=True)
    logotipo = models.ImageField(
        blank=True,
        null=True,
        upload_to='logotipos_entidades',
    )
    activo = models.BooleanField(choices=BOOL_ACTIVO, default=True)
    slug = models.SlugField(
        editable=False,
        max_length=255,
        unique=True,
        db_index=True,
    )

    #Métodos
    #Python 3.X
    def __str__(self):
        return self.get_nombre()

    #Python 2.X
    #def __unicode__(self):
    #	return self.nombre

    def save(self, *args, **kwargs):
        if not self.pk:
            self.slug = slugify(self.get_nombre())
        else:
            slug = slugify(self.get_nombre())
            if self.slug != slug:
                self.slug = slug
        super(Entidad, self).save(*args, **kwargs)

    def get_nombre(self):
        return self.nombre

    def get_siglas(self):
        return self.siglas

    #Opciones
    class Meta:
        #Nombre para la tabla del gestor de base de datos
        db_table = 'Entidades'
        #Ordenar los registros por un campo especifico
        ordering = ('nombre', )
        #Nombre para el Conjunto de Objetos en el Panel de Administración
        verbose_name = 'Entidad'
        #Nombre en Plural en la lista de módulos en el Panel de Administración
        verbose_name_plural = 'Entidades'  #Métodos
Beispiel #10
0
def get_config_variables():
    """
    Generator which yields all config variables of this app.

    There are two main groups: 'General' and 'Projector'. The group 'General'
    has subgroups. The generator has to be evaluated during app loading
    (see apps.py).
    """
    yield ConfigVariable(
        name="general_event_name",
        default_value="OpenSlides",
        label="Event name",
        weight=110,
        subgroup="Event",
        validators=(MaxLengthValidator(100), ),
    )

    yield ConfigVariable(
        name="general_event_description",
        default_value="Presentation and assembly system",
        label="Short description of event",
        weight=115,
        subgroup="Event",
        validators=(MaxLengthValidator(100), ),
    )

    yield ConfigVariable(
        name="general_event_date",
        default_value="",
        label="Event date",
        weight=120,
        subgroup="Event",
    )

    yield ConfigVariable(
        name="general_event_location",
        default_value="",
        label="Event location",
        weight=125,
        subgroup="Event",
    )

    yield ConfigVariable(
        name="general_event_legal_notice",
        default_value='<a href="http://www.openslides.org">OpenSlides</a> is a '
        "free web based presentation and assembly system for "
        "visualizing and controlling agenda, motions and "
        "elections of an assembly.",
        input_type="markupText",
        label="Legal notice",
        weight=131,
        subgroup="Event",
        hidden=True,
    )

    yield ConfigVariable(
        name="general_event_privacy_policy",
        default_value="",
        input_type="markupText",
        label="Privacy policy",
        weight=132,
        subgroup="Event",
        hidden=True,
    )

    yield ConfigVariable(
        name="general_event_welcome_title",
        default_value="Welcome to OpenSlides",
        label="Front page title",
        weight=133,
        subgroup="Event",
        hidden=True,
    )

    yield ConfigVariable(
        name="general_event_welcome_text",
        default_value="[Space for your welcome text.]",
        input_type="markupText",
        label="Front page text",
        weight=134,
        subgroup="Event",
        hidden=True,
    )

    # Live conference

    yield ConfigVariable(
        name="general_system_conference_show",
        default_value=False,
        input_type="boolean",
        label="Show live conference window",
        help_text=
        "Server settings required to activate Jitsi Meet integration.",
        weight=140,
        subgroup="Live conference",
    )

    yield ConfigVariable(
        name="general_system_conference_los_restriction",
        default_value=False,
        input_type="boolean",
        label=
        "Allow only current speakers and list of speakers managers to enter the live conference",
        help_text=
        "Server settings required to activate Jitsi Meet integration.",
        weight=141,
        subgroup="Live conference",
    )

    yield ConfigVariable(
        name="general_system_conference_auto_connect",
        default_value=False,
        input_type="boolean",
        label="Connect all users to live conference automatically",
        help_text=
        "Server settings required to activate Jitsi Meet integration.",
        weight=142,
        subgroup="Live conference",
    )

    yield ConfigVariable(
        name="general_system_conference_open_microphone",
        default_value=False,
        input_type="boolean",
        label="Automatically open the microphone for new conference speakers",
        help_text=
        "Server settings required to activate Jitsi Meet integration.",
        weight=143,
        subgroup="Live conference",
    )

    yield ConfigVariable(
        name="general_system_conference_open_video",
        default_value=False,
        input_type="boolean",
        label="Automatically open the web cam for new conference speakers",
        help_text=
        "Server settings required to activate Jitsi Meet integration.",
        weight=144,
        subgroup="Live conference",
    )

    yield ConfigVariable(
        name="general_system_conference_auto_connect_next_speakers",
        default_value=0,
        input_type="integer",
        label=
        "Number of next speakers automatically connecting to the live conference",
        help_text=
        "Live conference has to be active. Choose 0 to disable auto connect.",
        weight=145,
        subgroup="Live conference",
    )

    yield ConfigVariable(
        name="general_system_stream_url",
        default_value="",
        label="Livestream url",
        help_text=
        "Remove URL to deactivate livestream. Check extra group permission to see livestream.",
        weight=146,
        subgroup="Live conference",
    )

    yield ConfigVariable(
        name="general_system_stream_poster",
        default_value="",
        label="Livestream poster image url",
        help_text=
        "Shows if livestream is not started. Recommended image format: 500x280px, PNG or JPG",
        weight=147,
        subgroup="Live conference",
    )

    yield ConfigVariable(
        name="general_system_conference_enable_helpdesk",
        default_value=False,
        input_type="boolean",
        label="Enable virtual help desk room",
        help_text="""
            Shows a button with help icon to connect to an extra Jitsi conference room for technical audio/video tests.
        """,
        weight=148,
        subgroup="Live conference",
    )

    # Applause

    yield ConfigVariable(
        name="general_system_applause_enable",
        default_value=False,
        input_type="boolean",
        label="Enable virtual applause",
        weight=150,
        subgroup="Virtual applause",
    )

    yield ConfigVariable(
        name="general_system_applause_type",
        default_value="applause-type-bar",
        input_type="choice",
        choices=(
            {
                "value": "applause-type-bar",
                "display_name": "Level indicator",
            },
            {
                "value": "applause-type-particles",
                "display_name": "Particles",
            },
        ),
        label="Applause visualization",
        weight=151,
        subgroup="Virtual applause",
    )

    yield ConfigVariable(
        name="general_system_applause_show_level",
        default_value=False,
        input_type="boolean",
        label="Show applause amount",
        weight=152,
        subgroup="Virtual applause",
    )

    yield ConfigVariable(
        name="general_system_applause_min_amount",
        default_value=1,
        input_type="integer",
        label="Lowest applause amount",
        help_text=
        "Defines the minimum deflection which is required to recognize applause.",
        weight=153,
        subgroup="Virtual applause",
    )

    yield ConfigVariable(
        name="general_system_applause_max_amount",
        default_value=0,
        input_type="integer",
        label="Highest applause amount",
        help_text=
        "Defines the maximum deflection. Entering zero will use the amount of present participants instead.",
        weight=154,
        subgroup="Virtual applause",
    )

    yield ConfigVariable(
        name="general_system_stream_applause_timeout",
        default_value=5,
        input_type="integer",
        label="Applause interval in seconds",
        help_text="Defines the time in which applause amounts are add up.",
        weight=155,
        subgroup="Virtual applause",
    )

    yield ConfigVariable(
        name="general_system_applause_particle_image",
        default_value="",
        label="Applause particle image URL",
        help_text=
        "Shows the given image as applause particle. Recommended image format: 24x24px, PNG, JPG or SVG",
        weight=156,
        subgroup="Virtual applause",
    )

    # General System

    yield ConfigVariable(
        name="general_system_enable_anonymous",
        default_value=False,
        input_type="boolean",
        label="Allow access for anonymous guest users",
        weight=160,
        subgroup="System",
    )

    yield ConfigVariable(
        name="general_login_info_text",
        default_value="",
        label="Show this text on the login page",
        weight=162,
        subgroup="System",
    )

    yield ConfigVariable(
        name="openslides_theme",
        default_value="openslides-default-light-theme",
        input_type="choice",
        label="OpenSlides Theme",
        choices=(
            {
                "value": "openslides-default-light-theme",
                "display_name": "OpenSlides Default",
            },
            {
                "value": "openslides-default-dark-theme",
                "display_name": "OpenSlides Dark",
            },
            {
                "value": "openslides-red-light-theme",
                "display_name": "OpenSlides Red"
            },
            {
                "value": "openslides-red-dark-theme",
                "display_name": "OpenSlides Red Dark",
            },
            {
                "value": "openslides-green-light-theme",
                "display_name": "OpenSlides Green",
            },
            {
                "value": "openslides-green-dark-theme",
                "display_name": "OpenSlides Green Dark",
            },
            {
                "value": "openslides-solarized-dark-theme",
                "display_name": "OpenSlides Solarized",
            },
        ),
        weight=164,
        subgroup="System",
    )

    # General export settings

    yield ConfigVariable(
        name="general_csv_separator",
        default_value=",",
        label="Separator used for all csv exports and examples",
        weight=170,
        subgroup="Export",
    )

    yield ConfigVariable(
        name="general_csv_encoding",
        default_value="utf-8",
        input_type="choice",
        label="Default encoding for all csv exports",
        choices=(
            {
                "value": "utf-8",
                "display_name": "UTF-8"
            },
            {
                "value": "iso-8859-15",
                "display_name": "ISO-8859-15"
            },
        ),
        weight=172,
        subgroup="Export",
    )

    yield ConfigVariable(
        name="general_export_pdf_pagenumber_alignment",
        default_value="center",
        input_type="choice",
        label="Page number alignment in PDF",
        choices=(
            {
                "value": "left",
                "display_name": "Left"
            },
            {
                "value": "center",
                "display_name": "Center"
            },
            {
                "value": "right",
                "display_name": "Right"
            },
        ),
        weight=174,
        subgroup="Export",
    )

    yield ConfigVariable(
        name="general_export_pdf_fontsize",
        default_value="10",
        input_type="choice",
        label="Standard font size in PDF",
        choices=(
            {
                "value": "10",
                "display_name": "10"
            },
            {
                "value": "11",
                "display_name": "11"
            },
            {
                "value": "12",
                "display_name": "12"
            },
        ),
        weight=176,
        subgroup="Export",
    )

    yield ConfigVariable(
        name="general_export_pdf_pagesize",
        default_value="A4",
        input_type="choice",
        label="Standard page size in PDF",
        choices=(
            {
                "value": "A4",
                "display_name": "DIN A4"
            },
            {
                "value": "A5",
                "display_name": "DIN A5"
            },
        ),
        weight=178,
        subgroup="Export",
    )

    # Logos
    yield ConfigVariable(
        name="logos_available",
        default_value=[
            "logo_projector_main",
            "logo_projector_header",
            "logo_web_header",
            "logo_pdf_header_L",
            "logo_pdf_header_R",
            "logo_pdf_footer_L",
            "logo_pdf_footer_R",
            "logo_pdf_ballot_paper",
        ],
        weight=300,
        group="Logo",
        hidden=True,
    )

    yield ConfigVariable(
        name="logo_projector_main",
        default_value={
            "display_name": "Projector logo",
            "path": ""
        },
        input_type="static",
        weight=301,
        group="Logo",
        hidden=True,
    )

    yield ConfigVariable(
        name="logo_projector_header",
        default_value={
            "display_name": "Projector header image",
            "path": ""
        },
        input_type="static",
        weight=302,
        group="Logo",
        hidden=True,
    )

    yield ConfigVariable(
        name="logo_web_header",
        default_value={
            "display_name": "Web interface header logo",
            "path": ""
        },
        input_type="static",
        weight=303,
        group="Logo",
        hidden=True,
    )

    # PDF logos
    yield ConfigVariable(
        name="logo_pdf_header_L",
        default_value={
            "display_name": "PDF header logo (left)",
            "path": ""
        },
        input_type="static",
        weight=310,
        group="Logo",
        hidden=True,
    )

    yield ConfigVariable(
        name="logo_pdf_header_R",
        default_value={
            "display_name": "PDF header logo (right)",
            "path": ""
        },
        input_type="static",
        weight=311,
        group="Logo",
        hidden=True,
    )

    yield ConfigVariable(
        name="logo_pdf_footer_L",
        default_value={
            "display_name": "PDF footer logo (left)",
            "path": ""
        },
        input_type="static",
        weight=312,
        group="Logo",
        hidden=True,
    )

    yield ConfigVariable(
        name="logo_pdf_footer_R",
        default_value={
            "display_name": "PDF footer logo (right)",
            "path": ""
        },
        input_type="static",
        weight=313,
        group="Logo",
        hidden=True,
    )

    yield ConfigVariable(
        name="logo_pdf_ballot_paper",
        default_value={
            "display_name": "PDF ballot paper logo",
            "path": ""
        },
        input_type="static",
        weight=314,
        group="Logo",
        hidden=True,
    )

    # Fonts
    yield ConfigVariable(
        name="fonts_available",
        default_value=[
            "font_regular",
            "font_italic",
            "font_bold",
            "font_bold_italic",
            "font_monospace",
            "font_chyron_speaker_name",
        ],
        weight=320,
        group="Font",
        hidden=True,
    )

    yield ConfigVariable(
        name="font_regular",
        default_value={
            "display_name": "Font regular",
            "default": "assets/fonts/fira-sans-latin-400.woff",
            "path": "",
        },
        input_type="static",
        weight=321,
        group="Font",
        hidden=True,
    )

    yield ConfigVariable(
        name="font_italic",
        default_value={
            "display_name": "Font italic",
            "default": "assets/fonts/fira-sans-latin-400italic.woff",
            "path": "",
        },
        input_type="static",
        weight=321,
        group="Font",
        hidden=True,
    )

    yield ConfigVariable(
        name="font_bold",
        default_value={
            "display_name": "Font bold",
            "default": "assets/fonts/fira-sans-latin-500.woff",
            "path": "",
        },
        input_type="static",
        weight=321,
        group="Font",
        hidden=True,
    )

    yield ConfigVariable(
        name="font_bold_italic",
        default_value={
            "display_name": "Font bold italic",
            "default": "assets/fonts/fira-sans-latin-500italic.woff",
            "path": "",
        },
        input_type="static",
        weight=321,
        group="Font",
        hidden=True,
    )

    yield ConfigVariable(
        name="font_monospace",
        default_value={
            "display_name": "Font monospace",
            "default": "assets/fonts/roboto-condensed-bold.woff",
            "path": "",
        },
        input_type="static",
        weight=321,
        group="Font",
        hidden=True,
    )

    yield ConfigVariable(
        name="font_chyron_speaker_name",
        default_value={
            "display_name": "Font for speaker name (chyron)",
            "default": "assets/fonts/fira-sans-latin-400.woff",
            "path": "",
        },
        input_type="static",
        weight=321,
        group="Font",
        hidden=True,
    )

    # Custom translations
    yield ConfigVariable(
        name="translations",
        label="Custom translations",
        default_value=[],
        input_type="translations",
        weight=1000,
        group="Custom translations",
    )

    # Config version and DB id
    yield ConfigVariable(
        name="config_version",
        input_type="integer",
        default_value=1,
        group="Version",
        hidden=True,
    )
    yield ConfigVariable(
        name="db_id",
        input_type="string",
        default_value=uuid.uuid4().hex,
        group="Version",
        hidden=True,
    )
Beispiel #11
0
 def __init__(self, *args, **kwargs):
     max_length = kwargs.pop('max_length', None)
     super(LimitedTextField, self).__init__(*args, **kwargs)
     if max_length:
         self.validators += [MaxLengthValidator(max_length)]
Beispiel #12
0
 def __call__(self):
     try:
         MaxLengthValidator(64000)(self.content)
     except ValidationError as exc:
         raise RecordContentValidationError(exc.message)
Beispiel #13
0
class Issue(TCMSActionModel):
    """This is the issue which could be added to case or case run

    The meaning of issue in issue tracker represents a general concept. In
    different concrete issue tracker products, it has different name to call,
    e.g. bug in Bugzilla and issue in JIRA and GitHub.
    """

    issue_key = models.CharField(
        max_length=50,
        help_text='Actual issue ID corresponding issue tracker. Different '
        'issue tracker may have issue IDs in different type or '
        'format. For example, in Bugzilla, it could be an integer, '
        'or in JIRA, it could be a string in format '
        'PROJECTNAME-number, e.g. PROJECT-1000.',
        validators=[
            MaxLengthValidator(
                50, 'Issue key has too many characters. '
                'It should have 50 characters at most.')
        ])

    summary = models.CharField(max_length=255,
                               null=True,
                               blank=True,
                               help_text='Summary of issue.')

    description = models.TextField(null=True,
                                   blank=True,
                                   help_text='Description of issue.')

    tracker = models.ForeignKey(
        IssueTracker,
        related_name='issues',
        help_text='Which issue tracker this issue belongs to.',
        on_delete=models.CASCADE)
    case = models.ForeignKey(
        'testcases.TestCase',
        related_name='issues',
        help_text='A test case this issue is associated with.',
        error_messages={'required': 'Case is missed.'},
        on_delete=models.CASCADE)
    case_run = models.ForeignKey(
        'testruns.TestCaseRun',
        null=True,
        blank=True,
        related_name='issues',
        help_text='A test case run this issue is associated with optionally.',
        on_delete=models.SET_NULL)

    def __str__(self):
        return self.issue_key

    class Meta:
        db_table = 'issue_tracker_issues'
        unique_together = (
            ('tracker', 'issue_key', 'case'),
            ('tracker', 'issue_key', 'case', 'case_run'),
        )

    def get_absolute_url(self):
        return self.tracker.issue_url_fmt.format(product=self.tracker.name,
                                                 issue_key=self.issue_key)

    def clean(self):
        """Validate issue"""
        super().clean()

        issue_key_re = re.compile(self.tracker.validate_regex)
        if not issue_key_re.match(self.issue_key):
            raise ValidationError({
                'issue_key':
                'Issue key {} is in wrong format for issue tracker {}.'.format(
                    self.issue_key, self.tracker)
            })

    @staticmethod
    def count_by_case_run(case_run_ids=None):
        """Subtotal issues and optionally by specified case runs

        :param case_run_ids: list of test case run IDs to just return subtotal
            for them.
        :type case_run_ids: list[int]
        :return: a mapping from case run id to the number of issues belong to
            that case run.
        :rtype: dict
        """
        if case_run_ids is not None:
            assert isinstance(case_run_ids, list)
            assert all(isinstance(item, int) for item in case_run_ids)
            criteria = {'case_run__in': case_run_ids}
        else:
            criteria = {'case_run__isnull': False}
        return {
            item['case_run']: item['issues_count']
            for item in (Issue.objects.filter(
                **criteria).values('case_run').annotate(
                    issues_count=Count('pk')))
        }
Beispiel #14
0
class IssueTracker(TCMSActionModel):
    """Represent a deployed issue tracker instance"""

    enabled = models.BooleanField(
        default=True,
        db_index=True,
        help_text='Whether to enable this issue tracker in system wide.')
    name = models.CharField(
        max_length=50,
        unique=True,
        help_text='Issue tracker name.',
        validators=[
            MaxLengthValidator(50, message='Issue tracker name is too long.'),
            RegexValidator(
                r'^[a-zA-Z0-9 ]+$',
                message='Name contains invalid characters. Name could contain'
                ' lower and upper case letters, digit or space.')
        ])
    description = models.CharField(
        max_length=255,
        blank=True,
        default='',
        help_text='A short description to this issue tracker.')
    service_url = models.URLField(default='',
                                  blank=True,
                                  help_text='URL of this issue tracker.')
    api_url = models.URLField(default='',
                              blank=True,
                              help_text='API URL of this issue tracker.')

    issues_display_url_fmt = models.URLField(
        help_text='URL format to construct a display URL used to open in Web '
        'browse to display issues. For example, '
        'http://bugzilla.example.com/buglist.cgi?bug_id={issue_keys}')

    issue_url_fmt = models.URLField(
        help_text='Formatter string used to construct a specific issue\'s URL.'
        ' Format arguments: issue_key, product. For example,'
        ' https://bugzilla.domain/show_bug.cgi?id=%(issue_key)s')

    validate_regex = models.CharField(
        max_length=100,
        help_text='Regular expression in Python Regular Expression syntax, '
        'which is used to validate issue ID. This regex will be '
        'used in both JavaScript code and Python code. So, please '
        'write it carefully.',
        validators=[validators.validate_reg_exp])

    allow_add_case_to_issue = models.BooleanField(
        default=False,
        help_text='Allow to add associated test case link to issue.')

    credential_type = models.CharField(max_length=10,
                                       choices=[
                                           (item.name, item.value)
                                           for item in list(CredentialTypes)
                                       ],
                                       help_text='Type of credential')

    tracker_product = models.ForeignKey(IssueTrackerProduct,
                                        related_name='tracker_instances',
                                        on_delete=models.CASCADE)

    products = models.ManyToManyField('management.Product',
                                      through=ProductIssueTrackerRelationship,
                                      related_name='issue_trackers')

    # Field for loading corresponding Python class to do specific actions
    class_path = models.CharField(
        max_length=100,
        default='tcms.issuetracker.services.IssueTrackerService',
        help_text='Importable path to the implementation for this issue '
        'tracker. Default is '
        '<code>tcms.issuetracker.models.IssueTrackerService</code>, '
        'which provides basic functionalities for general purpose. '
        'Set to a custom path for specific class inherited from '
        '<code>IssueTrackerService</code>',
        validators=[validators.validate_class_path])

    # Fields for implementing filing issue in an issue tracker.

    issue_report_endpoint = models.CharField(
        max_length=50,
        help_text='The endpoint of this issue tracker service to file an '
        'issue.')

    issue_report_params = models.TextField(
        max_length=255,
        blank=True,
        default='',
        help_text='Parameters used to format URL for reporting issue. '
        'Each line is a <code>key:value</code> pair of parameters. '
        'Nitrate provides a few parameters to format URL and '
        'additional parameters could be provided by system '
        'administrator as well.',
        validators=[validators.validate_issue_report_params])

    issue_report_templ = models.TextField(
        max_length=255,
        blank=True,
        default='',
        help_text='The issue content template, which could be arbitrary text '
        'with format arguments. Nitrate provides these format '
        'arguments: <code>TestBuild.name</code>, '
        '<code>setup</code>, <code>action</code> and '
        '<code>effect</code>. The text is formatted with keyward '
        'arguments.')

    class Meta:
        db_table = 'issue_trackers'

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        """Get URL linking to this issue tracker

        :return: the URL.
        :rtype: str
        """
        return self.service_url

    @property
    def code_name(self):
        """Return a useful issue tracker name for programmatic purpose

        Several characters are replaced. Space in name is replaced with
        underscore.

        :return: a formatted name.
        :rtype: str
        """
        return self.name.replace(' ', '_')

    @classmethod
    def get_by_case(cls, case):
        """Find out issue trackers for a case

        :return: a queryset of matched issue trackers
        :rtype: QuerySet
        """
        return cls.objects.filter(products__in=case.plan.values('product'))

    @property
    def credential(self):
        """Get login credential

        The returned credential could contain different login credential data
        which depends on what credential type is configured for this issue
        tracker, and how corresponding credential is created.
        """
        if self.credential_type == CredentialTypes.NoNeed.name:
            return {}
        elif self.credential_type == CredentialTypes.UserPwd.name:
            cred = UserPwdCredential.objects.filter(issue_tracker=self).first()
            if cred is None:
                raise ValueError(
                    'Username/password credential is not set for issue tracker {}.'
                    .format(self.name))
            else:
                if cred.secret_file:
                    content = cred.read_secret_file(cred.secret_file)
                    return {
                        'username': content.get('issuetracker', 'username'),
                        'password': content.get('issuetracker', 'password'),
                    }
                else:
                    return {
                        'username': cred.username,
                        'password': cred.password,
                    }
        elif self.credential_type == CredentialTypes.Token.name:
            cred = TokenCredential.objects.filter(issue_tracker=self).first()
            if cred is None:
                raise ValueError(
                    'Token credential is not set for issue tracker {}.'.format(
                        self.name))
            else:
                if cred.secret_file:
                    content = cred.read_secret_file(cred.secret_file)
                    return {'token': content.get('issuetracker', 'token')}
                else:
                    return {'token': cred.token}
Beispiel #15
0
 (int_list_validator(sep='.'), '1.2.3\n', ValidationError),
 (MaxValueValidator(10), 10, None),
 (MaxValueValidator(10), -10, None),
 (MaxValueValidator(10), 0, None),
 (MaxValueValidator(NOW), NOW, None),
 (MaxValueValidator(NOW), NOW - timedelta(days=1), None),
 (MaxValueValidator(0), 1, ValidationError),
 (MaxValueValidator(NOW), NOW + timedelta(days=1), ValidationError),
 (MinValueValidator(-10), -10, None),
 (MinValueValidator(-10), 10, None),
 (MinValueValidator(-10), 0, None),
 (MinValueValidator(NOW), NOW, None),
 (MinValueValidator(NOW), NOW + timedelta(days=1), None),
 (MinValueValidator(0), -1, ValidationError),
 (MinValueValidator(NOW), NOW - timedelta(days=1), ValidationError),
 (MaxLengthValidator(10), '', None),
 (MaxLengthValidator(10), 10 * 'x', None),
 (MaxLengthValidator(10), 15 * 'x', ValidationError),
 (MinLengthValidator(10), 15 * 'x', None),
 (MinLengthValidator(10), 10 * 'x', None),
 (MinLengthValidator(10), '', ValidationError),
 (URLValidator(EXTENDED_SCHEMES), 'file://localhost/path', None),
 (URLValidator(EXTENDED_SCHEMES), 'git://example.com/', None),
 (URLValidator(EXTENDED_SCHEMES),
  'git+ssh://[email protected]/example/hg-git.git', None),
 (URLValidator(EXTENDED_SCHEMES), 'git://-invalid.com', ValidationError),
 # Trailing newlines not accepted
 (URLValidator(), 'http://www.djangoproject.com/\n', ValidationError),
 (URLValidator(), 'http://[::ffff:192.9.5.5]\n', ValidationError),
 # Trailing junk does not take forever to reject
 (URLValidator(), 'http://www.asdasdasdasdsadfm.com.br ', ValidationError),
class Course(Model):

    course_code = CharField()
    teaches = CharField()
    number_of_credits = PositiveSmallIntegerField(
        validators=[MaxLengthValidator(10)])
class CourseForm(BaseForm):
    organization = forms.ModelChoiceField(queryset=Organization.objects.filter(
        organization_extension__organization_id__isnull=False).order_by(
            Lower('key')),
                                          label=_('Organization Name'),
                                          required=True)
    title = forms.CharField(label=_('Course Title'),
                            required=True,
                            validators=[MaxLengthValidator(255)])
    number = forms.CharField(label=_('Course Number'),
                             required=True,
                             validators=[MaxLengthValidator(50)])
    short_description = forms.CharField(label=_('Short Description'),
                                        widget=forms.Textarea,
                                        required=False,
                                        validators=[MaxLengthValidator(350)])
    full_description = forms.CharField(label=_('Long Description'),
                                       widget=forms.Textarea,
                                       required=False,
                                       validators=[MaxLengthValidator(2500)])
    prerequisites = forms.CharField(label=_('Prerequisites'),
                                    widget=forms.Textarea,
                                    required=False,
                                    validators=[MaxLengthValidator(1000)])

    # users will be loaded through AJAX call based on organization
    team_admin = UserModelChoiceField(
        queryset=User.objects.none(),
        required=True,
        label=_('Organization Course Admin'),
    )

    subjects = Subject.objects.all().order_by('translations__name')
    primary_subject = forms.ModelChoiceField(queryset=subjects,
                                             label=_('Primary'),
                                             required=False)
    secondary_subject = forms.ModelChoiceField(
        queryset=subjects,
        label=_('Additional Subject (optional)'),
        required=False)
    tertiary_subject = forms.ModelChoiceField(
        queryset=subjects,
        label=_('Additional Subject (optional)'),
        required=False)

    level_type = forms.ModelChoiceField(
        queryset=LevelType.objects.all().order_by('-name'),
        label=_('Level'),
        required=False)

    expected_learnings = forms.CharField(label=_('What You Will Learn'),
                                         widget=forms.Textarea,
                                         required=False,
                                         validators=[MaxLengthValidator(2500)])

    learner_testimonial = forms.CharField(label=_('Learner Testimonial'),
                                          widget=forms.Textarea,
                                          required=False,
                                          validators=[MaxLengthValidator(500)])

    faq = forms.CharField(label=_('FAQ'),
                          widget=forms.Textarea,
                          required=False,
                          validators=[MaxLengthValidator(2500)])

    syllabus = forms.CharField(label=_('Syllabus'),
                               widget=forms.Textarea,
                               required=False,
                               validators=[MaxLengthValidator(2500)])

    add_new_run = forms.BooleanField(required=False)

    class Meta:
        model = Course
        widgets = {'image': ClearableImageInput(attrs={'accept': 'image/*'})}
        fields = (
            'title',
            'number',
            'short_description',
            'full_description',
            'expected_learnings',
            'primary_subject',
            'secondary_subject',
            'tertiary_subject',
            'prerequisites',
            'image',
            'team_admin',
            'level_type',
            'organization',
            'is_seo_review',
            'syllabus',
            'learner_testimonial',
            'faq',
            'video_link',
        )

    def __init__(self, *args, **kwargs):
        # In case of edit mode pre-populate the drop-downs
        user = kwargs.pop('user', None)
        organization = kwargs.pop('organization', None)
        if organization:
            org_extension = OrganizationExtension.objects.get(
                organization=organization)
            self.declared_fields['team_admin'].queryset = User.objects.filter(
                groups__name=org_extension.group).order_by(
                    'full_name', 'username')

        if user:
            self.declared_fields[
                'organization'].queryset = get_user_organizations(user)
            self.declared_fields['team_admin'].widget.attrs = {
                'data-user': user.id
            }

        super(CourseForm, self).__init__(*args, **kwargs)

        if user and not is_internal_user(user):
            self.fields['video_link'].widget = forms.HiddenInput()

    def clean_title(self):
        """
        Convert all named and numeric character references in the string
        to the corresponding unicode characters
        """
        return html.unescape(self.cleaned_data.get('title'))

    def clean_number(self):
        """
        Validate that number doesn't consist of any special characters other than period, underscore or hyphen
        """
        number = self.cleaned_data.get('number')
        if not VALID_CHARS_IN_COURSE_NUM_AND_ORG_KEY.match(number):
            raise ValidationError(
                _('Please do not use any spaces or special characters other than period, '
                  'underscore or hyphen.'))
        return number

    def clean(self):
        cleaned_data = self.cleaned_data
        organization = cleaned_data.get('organization')
        title = cleaned_data.get('title')
        number = cleaned_data.get('number')
        instance = getattr(self, 'instance', None)
        if not instance.pk:
            if Course.objects.filter(title=title,
                                     organizations__in=[organization
                                                        ]).exists():
                raise ValidationError(
                    {'title': _('This course title already exists')})
            if Course.objects.filter(number=number,
                                     organizations__in=[organization
                                                        ]).exists():
                raise ValidationError(
                    {'number': _('This course number already exists')})
        return cleaned_data
class Outward(BaseDate):
    """
    This is a tool that can be used to send out newsletters or important communications to your community.
    It's aimed to be useful and flexible.
    """
    status = models.IntegerField(_('status'),
                                 choices=OUTWARD_STATUS_CHOICES,
                                 default=OUTWARD_STATUS.get('draft'))
    subject = models.CharField(_('subject'), max_length=50)
    message = models.TextField(_('message'),
                               validators=[
                                   MinLengthValidator(OUTWARD_MINLENGTH),
                                   MaxLengthValidator(OUTWARD_MAXLENGTH)
                               ])
    is_scheduled = models.SmallIntegerField(_('schedule sending'),
                                            choices=SCHEDULE_CHOICES,
                                            default=0)
    scheduled_date = models.DateField(_('scheduled date'),
                                      blank=True,
                                      null=True)
    scheduled_time = models.CharField(_('scheduled time'),
                                      max_length=20,
                                      choices=OUTWARD_SCHEDULING,
                                      default=OUTWARD_SCHEDULING[0][0],
                                      blank=True)
    is_filtered = models.SmallIntegerField(_('recipient filtering'),
                                           choices=FILTERING_CHOICES,
                                           default=0)
    filters = MultiSelectField(max_length=255,
                               choices=FILTER_CHOICES,
                               blank=True,
                               help_text=_('specify recipient filters'))
    groups = MultiSelectField(max_length=255,
                              choices=GROUPS,
                              default=DEFAULT_GROUPS,
                              blank=True,
                              help_text=_('filter specific groups of users'))

    if 'nodeshot.core.layers' in settings.INSTALLED_APPS:
        layers = models.ManyToManyField('layers.Layer',
                                        verbose_name=_('layers'),
                                        blank=True)

    users = models.ManyToManyField(settings.AUTH_USER_MODEL,
                                   verbose_name=_('users'),
                                   blank=True)

    class Meta:
        verbose_name = _('Outward message')
        verbose_name_plural = _('Outward messages')
        app_label = 'mailing'
        ordering = ['status']

    def __unicode__(self):
        return '%s' % self.subject

    def get_recipients(self):
        """
        Determine recipients depending on selected filtering which can be either:
            * group based
            * layer based
            * user based

        Choosing "group" and "layer" filtering together has the effect of sending the message
        only to users for which the following conditions are both true:
            * have a node assigned to one of the selected layers
            * are part of any of the specified groups (eg: registered, community, trusted)

        The user based filtering has instead the effect of translating in an **OR** query. Here's a practical example:
        if selecting "group" and "user" filtering the message will be sent to all the users for which ANY of the following conditions is true:
            * are part of any of the specified groups (eg: registered, community, trusted)
            * selected users
        """
        # user model
        User = get_user_model()

        # prepare email list
        emails = []

        # the following code is a bit ugly. Considering the titanic amount of work required to build all
        # the cools functionalities that I have in my mind, I can't be bothered to waste time on making it nicer right now.
        # if you have ideas on how to improve it to make it cleaner and less cluttered, please join in
        # this method has unit tests written for it, therefore if you try to change it be sure to check unit tests do not fail after your changes
        # python manage.py test mailing

        # send to all case
        if not self.is_filtered:
            # retrieve only email DB column of all active users
            users = User.objects.filter(is_active=True).only('email')
            # loop over users list
            for user in users:
                # add email to the recipient list if not already there
                if user.email not in emails:
                    emails += [user.email]
        else:
            # selected users
            if FILTERS.get('users') in self.filters:
                # retrieve selected users
                users = self.users.all().only('email')
                # loop over selected users
                for user in users:
                    # add email to the recipient list if not already there
                    if user.email not in emails:
                        emails += [user.email]

            # Q is a django object for "complex" filtering queries (not that complex in this case)
            # init empty Q object that will be needed in case of group filtering
            q = Q()
            q2 = Q()

            # if group filtering is checked
            if FILTERS.get('groups') in self.filters:
                # loop over each group
                for group in self.groups:
                    # if not superusers
                    if group != '0':
                        # add the group to the Q object
                        # this means that the query will look for users of that specific group
                        q = q | Q(groups=int(group))
                        q2 = q2 | Q(user__groups=int(group))
                    else:
                        # this must be done manually because superusers is not a group but an attribute of the User model
                        q = q | Q(is_superuser=True)
                        q2 = q2 | Q(user__is_superuser=True)

            # plus users must be active
            q = q & Q(is_active=True)

            # if layer filtering is checked
            if FILTERS.get('layers') in self.filters:
                # retrieve non-external layers
                layers = self.layers.all().only('id')
                # init empty q3
                q3 = Q()
                # loop over layers to form q3 object
                for layer in layers:
                    q3 = q3 | Q(layer=layer)
                # q2: user group if present
                # q3: layers
                # retrieve nodes
                nodes = Node.objects.filter(q2 & q3)
                # loop over nodes of a layer and get their email
                for node in nodes:
                    # add email to the recipient list if not already there
                    if node.user.email not in emails:
                        emails += [node.user.email]
            # else if group filterins is checked but not layers
            elif FILTERS.get('groups') in self.filters and not FILTERS.get(
                    'layers') in self.filters:
                # retrieve only email DB column of all active users
                users = User.objects.filter(q).only('email')
                # loop over users list
                for user in users:
                    # add email to the recipient list if not already there
                    if user.email not in emails:
                        emails += [user.email]
        return emails

    def send(self):
        """
        Sends the email to the recipients
        """
        # if it has already been sent don't send again
        if self.status is OUTWARD_STATUS.get('sent'):
            return False
        # determine recipients
        recipients = self.get_recipients()
        # init empty list that will contain django's email objects
        emails = []

        # prepare text plain if necessary
        if OUTWARD_HTML:
            # store plain text in var
            html_content = self.message
            # set EmailClass to EmailMultiAlternatives
            EmailClass = EmailMultiAlternatives
        else:
            EmailClass = EmailMessage

        # default message is plain text
        message = strip_tags(self.message)

        # loop over recipients and fill "emails" list
        for recipient in recipients:
            msg = EmailClass(
                # subject
                self.subject,
                # message
                message,
                # from
                settings.DEFAULT_FROM_EMAIL,
                # to
                [recipient],
            )
            if OUTWARD_HTML:
                msg.attach_alternative(html_content, "text/html")
            # prepare email object
            emails.append(msg)

        # try sending email
        try:
            # counter will count how many emails have been sent
            counter = 0
            for email in emails:
                # if step reached
                if counter == OUTWARD_STEP:
                    # reset counter
                    counter = 0
                    # sleep
                    time.sleep(OUTWARD_DELAY)
                # send email
                email.send()
                # increase counter
                counter += 1
        # if error (connection refused, SMTP down)
        except socket.error as e:
            # log the error
            from logging import error
            error('nodeshot.core.mailing.models.outward.send(): %s' % e)
            # set status of the instance as "error"
            self.status = OUTWARD_STATUS.get('error')
        # change status
        self.status = OUTWARD_STATUS.get('sent')
        # save
        self.save()

    def save(self, *args, **kwargs):
        """
        Custom save method
        """
        # change status to scheduled if necessary
        if self.is_scheduled and self.status is not OUTWARD_STATUS.get(
                'scheduled'):
            self.status = OUTWARD_STATUS.get('scheduled')

        # call super.save()
        super(Outward, self).save(*args, **kwargs)

    def clean(self, *args, **kwargs):
        """
        Custom validation
        """
        if self.is_scheduled is 1 and (self.scheduled_date == ''
                                       or self.scheduled_date is None
                                       or self.scheduled_time == ''
                                       or self.scheduled_time is None):
            raise ValidationError(
                _('If message is scheduled both fields "scheduled date" and "scheduled time" must be specified'
                  ))

        if self.is_scheduled is 1 and self.scheduled_date < now().date():
            raise ValidationError(
                _('The scheduled date is set to a past date'))

        if self.is_filtered is 1 and (len(self.filters) < 1 or self.filters
                                      == [''] or self.filters == [u'']
                                      or self.filters == ''
                                      or self.filters is None):
            raise ValidationError(
                _('If "recipient filtering" is active one of the filtering options should be selected'
                  ))

        if self.is_filtered is 1 and FILTERS.get('groups') in self.filters and\
           (len(self.groups) < 1 or self.groups == [''] or self.groups == [u''] or self.groups == '' or self.groups is None):
            raise ValidationError(
                _('If group filtering is active at least one group of users should be selected'
                  ))
Beispiel #19
0
class Inward(BaseDate):
    """
    Incoming messages from users
    """
    # could be a node, an user or a layer
    status = models.IntegerField(_('status'),
                                 choices=INWARD_STATUS_CHOICES,
                                 default=INWARD_STATUS_CHOICES[1][0])
    content_type = models.ForeignKey(ContentType, limit_choices_to=limit)
    object_id = models.PositiveIntegerField()
    to = generic.GenericForeignKey('content_type', 'object_id')
    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             verbose_name=_('user'),
                             blank=USER_CAN_BE_BLANK,
                             null=True)
    from_name = models.CharField(_('name'), max_length=50, blank=True)
    from_email = models.EmailField(_('email'), max_length=50, blank=True)
    message = models.TextField(_('message'),
                               validators=[
                                   MaxLengthValidator(INWARD_MAXLENGTH),
                                   MinLengthValidator(INWARD_MINLENGTH)
                               ])
    ip = models.GenericIPAddressField(verbose_name=_('ip address'),
                                      blank=True,
                                      null=True)
    user_agent = models.CharField(max_length=255, blank=True)
    accept_language = models.CharField(max_length=255, blank=True)

    class Meta:
        verbose_name = _('Inward message')
        verbose_name_plural = _('Inward messages')
        app_label = 'mailing'
        ordering = ['-status']

    def __unicode__(self):
        return _(u'Message from %(from)s to %(to)s') % ({
            'from': self.from_name,
            'to': self.content_type
        })

    def clean(self, *args, **kwargs):
        """ custom validation """
        if not self.user and (not self.from_name or not self.from_email):
            raise ValidationError(
                _('If sender is not specified from_name and from_email must be filled in'
                  ))

        # fill name and email
        if self.user:
            self.from_name = self.user.get_full_name()
            self.from_email = self.user.email

    def send(self):
        """
        Sends the email to the recipient
        If the sending fails will set the status of the instance to "error" and will log the error according to your project's django-logging configuration
        """
        if self.content_type.name == 'node':
            to = [self.to.user.email]
        elif self.content_type.name == 'layer':
            to = [self.to.email]
            # layer case is slightly special, mantainers need to be notified as well
            # TODO: consider making the mantainers able to switch off notifications
            for mantainer in self.to.mantainers.all().only('email'):
                to += [mantainer.email]
        else:
            to = [self.to.email]

        email = EmailMessage(
            # subject
            _('Contact request from %(sender)s - %(site)s') % {
                'sender': self.from_name,
                'site': settings.SITE_NAME
            },
            # message
            self.message,
            # from
            settings.DEFAULT_FROM_EMAIL,
            # to
            to,
            # reply-to header
            headers={'Reply-To': self.from_email})

        import socket
        # try sending email
        try:
            email.send()
            self.status = 1
        # if error
        except socket.error as e:
            # log the error
            import logging
            log = logging.getLogger(__name__)
            error_msg = 'nodeshot.community.mailing.models.inward.send(): %s' % e
            log.error(error_msg)
            # set status of the instance as "error"
            self.status = -1

    def save(self, *args, **kwargs):
        """
        Custom save method
        """
        # fill name and email
        if self.user:
            self.from_name = self.user.get_full_name()
            self.from_email = self.user.email

        # if not sent yet
        if int(self.status) < 1:
            # tries sending email (will modify self.status!)
            self.send()

        # save in the database unless logging is explicitly turned off in the settings file
        if INWARD_LOG:
            super(Inward, self).save(*args, **kwargs)
class PhoneNumberConfirmation(models.Model):
    phone_number = models.ForeignKey(PhoneNumber,
                                     on_delete=models.CASCADE,
                                     related_name='phone_number')
    pin = models.IntegerField(verbose_name=_('pin'),
                              validators=[MaxLengthValidator(6)],
                              unique=True)
    sent = models.DateTimeField(verbose_name=_('sent'), null=True)

    class Meta:
        verbose_name = _("phone number confirmation")
        verbose_name_plural = _("Phone Number Confirmations")

    def __str__(self):
        return "%s (%s)" % (self.phone_number, self.pin)

    @classmethod
    def create(cls, phone_number):
        pin = randint(100000, 999999)
        return cls._default_manager.create(phone_number=phone_number, pin=pin)

    def pin_expired(self):
        expiration_date = self.sent + datetime.timedelta(
            minutes=app_settings.PHONE_CONFIRMATION_EXPIRE_MINUTES)
        return expiration_date <= timezone.now()

    def send_confirmation(self):
        if all([
                settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN,
                settings.TWILIO_FROM_NUMBER
        ]):
            try:
                twilio_client = Client(settings.TWILIO_ACCOUNT_SID,
                                       settings.TWILIO_AUTH_TOKEN)
                twilio_client.messages.create(
                    body="Your activation pin is %s" % self.pin,
                    to=str(self.phone_number.phone),
                    from_=settings.TWILIO_FROM_NUMBER)
                self.sent = timezone.now()
                self.save()
            except TwilioRestException as e:
                raise ValueError(e)
        else:
            raise ValueError(_("Twilio credentials are not set"))

    def resend_confirmation(self):
        if self.phone_number and (self.pin_expired()
                                  or not self.phone_number.verified):
            new_pin = randint(100000, 999999)
            self.pin = new_pin
            self.save()

            try:
                twilio_client = Client(settings.TWILIO_ACCOUNT_SID,
                                       settings.TWILIO_AUTH_TOKEN)
                twilio_client.messages.create(
                    body="Your activation pin is %s" % self.pin,
                    to=str(self.phone_number.phone),
                    from_=settings.TWILIO_FROM_NUMBER)
                self.sent = timezone.now()
                self.save()
            except TwilioRestException as e:
                raise ValueError(e)
        else:
            return PermissionError("Previous PIN not expired")

        return self.pin

    def confirmation(self, pin):
        if self.pin and self.pin == pin and self.phone_number and not self.pin_expired(
        ) and not self.phone_number.verified:
            self.phone_number.verified, self.phone_number.primary = True, True
            self.phone_number.save()
        else:
            raise ValueError(
                "your Pin is wrong or expired, or this phone is verified before."
            )
        return self.phone_number.verified
Beispiel #21
0
def get_config_variables():
    """
    Generator which yields all config variables of this app.

    There are two main groups: 'General' and 'Projector'. The group 'General'
    has subgroups. The generator has to be evaluated during app loading
    (see apps.py).
    """
    yield ConfigVariable(
        name="general_event_name",
        default_value="OpenSlides",
        label="Event name",
        weight=110,
        subgroup="Event",
        validators=(MaxLengthValidator(100), ),
    )

    yield ConfigVariable(
        name="general_event_description",
        default_value="Presentation and assembly system",
        label="Short description of event",
        weight=115,
        subgroup="Event",
        validators=(MaxLengthValidator(100), ),
    )

    yield ConfigVariable(
        name="general_event_date",
        default_value="",
        label="Event date",
        weight=120,
        subgroup="Event",
    )

    yield ConfigVariable(
        name="general_event_location",
        default_value="",
        label="Event location",
        weight=125,
        subgroup="Event",
    )

    yield ConfigVariable(
        name="general_event_legal_notice",
        default_value='<a href="http://www.openslides.org">OpenSlides</a> is a '
        "free web based presentation and assembly system for "
        "visualizing and controlling agenda, motions and "
        "elections of an assembly.",
        input_type="markupText",
        label="Legal notice",
        weight=131,
        subgroup="Event",
        hidden=True,
    )

    yield ConfigVariable(
        name="general_event_privacy_policy",
        default_value="",
        input_type="markupText",
        label="Privacy policy",
        weight=132,
        subgroup="Event",
        hidden=True,
    )

    yield ConfigVariable(
        name="general_event_welcome_title",
        default_value="Welcome to OpenSlides",
        label="Front page title",
        weight=133,
        subgroup="Event",
        hidden=True,
    )

    yield ConfigVariable(
        name="general_event_welcome_text",
        default_value="[Space for your welcome text.]",
        input_type="markupText",
        label="Front page text",
        weight=134,
        subgroup="Event",
        hidden=True,
    )

    # Live conference

    yield ConfigVariable(
        name="general_system_conference_show",
        default_value=False,
        input_type="boolean",
        label="Show live conference window",
        help_text=
        "Server settings required to activate Jitsi Meet integration.",
        weight=140,
        subgroup="Live conference",
    )

    yield ConfigVariable(
        name="general_system_conference_auto_connect",
        default_value=False,
        input_type="boolean",
        label="Connect all users to live conference automatically",
        help_text=
        "Server settings required to activate Jitsi Meet integration.",
        weight=141,
        subgroup="Live conference",
    )

    yield ConfigVariable(
        name="general_system_conference_los_restriction",
        default_value=False,
        input_type="boolean",
        label=
        "Allow only current speakers and list of speakers managers to enter the live conference",
        help_text=
        "Server settings required to activate Jitsi Meet integration.",
        weight=142,
        subgroup="Live conference",
    )

    yield ConfigVariable(
        name="general_system_stream_url",
        default_value="",
        label="Livestream url",
        help_text=
        "Remove URL to deactivate livestream. Check extra group permission to see livestream.",
        weight=143,
        subgroup="Live conference",
    )

    # General System

    yield ConfigVariable(
        name="general_system_enable_anonymous",
        default_value=False,
        input_type="boolean",
        label="Allow access for anonymous guest users",
        weight=150,
        subgroup="System",
    )

    yield ConfigVariable(
        name="general_login_info_text",
        default_value="",
        label="Show this text on the login page",
        weight=152,
        subgroup="System",
    )

    yield ConfigVariable(
        name="openslides_theme",
        default_value="openslides-default-light-theme",
        input_type="choice",
        label="OpenSlides Theme",
        choices=(
            {
                "value": "openslides-default-light-theme",
                "display_name": "OpenSlides Default",
            },
            {
                "value": "openslides-default-dark-theme",
                "display_name": "OpenSlides Dark",
            },
            {
                "value": "openslides-red-light-theme",
                "display_name": "OpenSlides Red"
            },
            {
                "value": "openslides-red-dark-theme",
                "display_name": "OpenSlides Red Dark",
            },
            {
                "value": "openslides-green-light-theme",
                "display_name": "OpenSlides Green",
            },
            {
                "value": "openslides-green-dark-theme",
                "display_name": "OpenSlides Green Dark",
            },
            {
                "value": "openslides-solarized-dark-theme",
                "display_name": "OpenSlides Solarized",
            },
        ),
        weight=154,
        subgroup="System",
    )

    # General export settings

    yield ConfigVariable(
        name="general_csv_separator",
        default_value=",",
        label="Separator used for all csv exports and examples",
        weight=160,
        subgroup="Export",
    )

    yield ConfigVariable(
        name="general_csv_encoding",
        default_value="utf-8",
        input_type="choice",
        label="Default encoding for all csv exports",
        choices=(
            {
                "value": "utf-8",
                "display_name": "UTF-8"
            },
            {
                "value": "iso-8859-15",
                "display_name": "ISO-8859-15"
            },
        ),
        weight=162,
        subgroup="Export",
    )

    yield ConfigVariable(
        name="general_export_pdf_pagenumber_alignment",
        default_value="center",
        input_type="choice",
        label="Page number alignment in PDF",
        choices=(
            {
                "value": "left",
                "display_name": "Left"
            },
            {
                "value": "center",
                "display_name": "Center"
            },
            {
                "value": "right",
                "display_name": "Right"
            },
        ),
        weight=164,
        subgroup="Export",
    )

    yield ConfigVariable(
        name="general_export_pdf_fontsize",
        default_value="10",
        input_type="choice",
        label="Standard font size in PDF",
        choices=(
            {
                "value": "10",
                "display_name": "10"
            },
            {
                "value": "11",
                "display_name": "11"
            },
            {
                "value": "12",
                "display_name": "12"
            },
        ),
        weight=166,
        subgroup="Export",
    )

    yield ConfigVariable(
        name="general_export_pdf_pagesize",
        default_value="A4",
        input_type="choice",
        label="Standard page size in PDF",
        choices=(
            {
                "value": "A4",
                "display_name": "DIN A4"
            },
            {
                "value": "A5",
                "display_name": "DIN A5"
            },
        ),
        weight=168,
        subgroup="Export",
    )

    # Logos
    yield ConfigVariable(
        name="logos_available",
        default_value=[
            "logo_projector_main",
            "logo_projector_header",
            "logo_web_header",
            "logo_pdf_header_L",
            "logo_pdf_header_R",
            "logo_pdf_footer_L",
            "logo_pdf_footer_R",
            "logo_pdf_ballot_paper",
        ],
        weight=300,
        group="Logo",
        hidden=True,
    )

    yield ConfigVariable(
        name="logo_projector_main",
        default_value={
            "display_name": "Projector logo",
            "path": ""
        },
        input_type="static",
        weight=301,
        group="Logo",
        hidden=True,
    )

    yield ConfigVariable(
        name="logo_projector_header",
        default_value={
            "display_name": "Projector header image",
            "path": ""
        },
        input_type="static",
        weight=302,
        group="Logo",
        hidden=True,
    )

    yield ConfigVariable(
        name="logo_web_header",
        default_value={
            "display_name": "Web interface header logo",
            "path": ""
        },
        input_type="static",
        weight=303,
        group="Logo",
        hidden=True,
    )

    # PDF logos
    yield ConfigVariable(
        name="logo_pdf_header_L",
        default_value={
            "display_name": "PDF header logo (left)",
            "path": ""
        },
        input_type="static",
        weight=310,
        group="Logo",
        hidden=True,
    )

    yield ConfigVariable(
        name="logo_pdf_header_R",
        default_value={
            "display_name": "PDF header logo (right)",
            "path": ""
        },
        input_type="static",
        weight=311,
        group="Logo",
        hidden=True,
    )

    yield ConfigVariable(
        name="logo_pdf_footer_L",
        default_value={
            "display_name": "PDF footer logo (left)",
            "path": ""
        },
        input_type="static",
        weight=312,
        group="Logo",
        hidden=True,
    )

    yield ConfigVariable(
        name="logo_pdf_footer_R",
        default_value={
            "display_name": "PDF footer logo (right)",
            "path": ""
        },
        input_type="static",
        weight=313,
        group="Logo",
        hidden=True,
    )

    yield ConfigVariable(
        name="logo_pdf_ballot_paper",
        default_value={
            "display_name": "PDF ballot paper logo",
            "path": ""
        },
        input_type="static",
        weight=314,
        group="Logo",
        hidden=True,
    )

    # Fonts
    yield ConfigVariable(
        name="fonts_available",
        default_value=[
            "font_regular",
            "font_italic",
            "font_bold",
            "font_bold_italic",
            "font_monospace",
        ],
        weight=320,
        group="Font",
        hidden=True,
    )

    yield ConfigVariable(
        name="font_regular",
        default_value={
            "display_name": "Font regular",
            "default": "assets/fonts/fira-sans-latin-400.woff",
            "path": "",
        },
        input_type="static",
        weight=321,
        group="Font",
        hidden=True,
    )

    yield ConfigVariable(
        name="font_italic",
        default_value={
            "display_name": "Font italic",
            "default": "assets/fonts/fira-sans-latin-400italic.woff",
            "path": "",
        },
        input_type="static",
        weight=321,
        group="Font",
        hidden=True,
    )

    yield ConfigVariable(
        name="font_bold",
        default_value={
            "display_name": "Font bold",
            "default": "assets/fonts/fira-sans-latin-500.woff",
            "path": "",
        },
        input_type="static",
        weight=321,
        group="Font",
        hidden=True,
    )

    yield ConfigVariable(
        name="font_bold_italic",
        default_value={
            "display_name": "Font bold italic",
            "default": "assets/fonts/fira-sans-latin-500italic.woff",
            "path": "",
        },
        input_type="static",
        weight=321,
        group="Font",
        hidden=True,
    )

    yield ConfigVariable(
        name="font_monospace",
        default_value={
            "display_name": "Font monospace",
            "default": "assets/fonts/roboto-condensed-bold.woff",
            "path": "",
        },
        input_type="static",
        weight=321,
        group="Font",
        hidden=True,
    )

    # Custom translations
    yield ConfigVariable(
        name="translations",
        label="Custom translations",
        default_value=[],
        input_type="translations",
        weight=1000,
        group="Custom translations",
    )

    # Config version and DB id
    yield ConfigVariable(
        name="config_version",
        input_type="integer",
        default_value=1,
        group="Version",
        hidden=True,
    )
    yield ConfigVariable(
        name="db_id",
        input_type="string",
        default_value=uuid.uuid4().hex,
        group="Version",
        hidden=True,
    )
Beispiel #22
0
class Poll(models.Model):
    """Poll Model."""
    name = models.CharField(max_length=300)
    slug = models.SlugField(blank=True, max_length=255)
    start = models.DateTimeField()
    end = models.DateTimeField()
    valid_groups = models.ForeignKey(Group, related_name='valid_polls')
    created_on = models.DateTimeField(auto_now_add=True)
    description = models.TextField(
        validators=[MaxLengthValidator(1500),
                    MinLengthValidator(20)])
    created_by = models.ForeignKey(User, related_name='range_polls_created')
    users_voted = models.ManyToManyField(User,
                                         related_name='polls_voted',
                                         through='Vote')
    task_start_id = models.CharField(max_length=256,
                                     blank=True,
                                     null=True,
                                     editable=False,
                                     default='')
    task_end_id = models.CharField(max_length=256,
                                   blank=True,
                                   null=True,
                                   editable=False,
                                   default='')
    bug = models.ForeignKey(Bug, null=True, blank=True)
    automated_poll = models.BooleanField(default=False)
    comments_allowed = models.BooleanField(default=True)
    is_extended = models.BooleanField(default=False)

    def get_absolute_url(self):
        return reverse('remo.voting.views.view_voting', args=[self.slug])

    @property
    def is_future_voting(self):
        if self.start > now():
            return True
        return False

    @property
    def is_current_voting(self):
        if self.start < now() and self.end > now():
            return True
        return False

    @property
    def is_past_voting(self):
        if self.end < now():
            return True
        return False

    def __unicode__(self):
        return self.name

    class Meta:
        ordering = ['-created_on']

    def save(self, *args, **kwargs):
        if not self.pk:
            self.slug = uuslug(self.name, instance=self)
        else:
            if not settings.CELERY_ALWAYS_EAGER:
                if self.is_current_voting:
                    celery_control.revoke(self.task_end_id)
                elif self.is_future_voting:
                    celery_control.revoke(self.task_start_id)
                    celery_control.revoke(self.task_end_id)

            if not self.is_future_voting:
                obj = Poll.objects.get(pk=self.id)
                if self.end > obj.end:
                    self.is_extended = True

        super(Poll, self).save()
Beispiel #23
0
class Bank(models.Model):
    pwd = models.CharField(max_length=4)
    customer_name = models.CharField(max_length=20)
    card_number = models.IntegerField(
        validators=[MaxLengthValidator(6),
                    MinLengthValidator(6)])  # fix length 6
Beispiel #24
0
from django.db import models
from django.core.validators import MinLengthValidator, MaxLengthValidator

title_MinLenValidator = MinLengthValidator(2, "2자 이상 입력해주세요.(2자 ~ 80자 이내)")
title_MaxLenValidator = MaxLengthValidator(80, "80자 이내로 입력해주세요.(2자 ~ 80자 이내)")
contents_MinLenValidator = MinLengthValidator(10, "글이 너무 짧습니다. 10자 이상 입력해주세요.")


class TimeStampedModel(models.Model):
    """ Time Stamped Model """

    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True


class Department(models.Model):
    class Meta:
        verbose_name = "부서"
        verbose_name_plural = "부서"

    d_id = models.PositiveIntegerField(primary_key=True, verbose_name="부서ID")
    d_name = models.CharField(max_length=80, verbose_name="부서명")

    def __str__(self):
        return self.d_name


class Position(models.Model):
Beispiel #25
0
class Partner(PartnerModel):

    published = models.BooleanField(help_text=(
        "Partners without this checked will never be seen by the public"))
    logo = models.URLField(
        help_text=("The URL to the logo (e.g. http://example.com/logo.svg).\n"
                   "Please only upload .png and .svg files, "
                   "no less than 200 pixels wide.\n"))
    partner_website = models.URLField(
        help_text=("The URL to the partner's site "
                   "where the info about partnering with Canonical is."))
    fallback_website = models.URLField(help_text=(
        "If our partner changes their site without us realising it, "
        "and the 'external page' errors, this will be` used instead."))
    short_description = models.TextField(
        help_text=(
            "Used in search results, max 375 characters."
            "(<a href='http://daringfireball.net/projects/markdown/basics'>"
            "Markdown formatted"
            "</a>)"),
        validators=[MaxLengthValidator(375)],
    )
    long_description = models.TextField(
        blank=True,
        null=True,
        help_text=(
            "Only displayed on the dedicated partner page "
            "(when 'generate page' is selected). "
            "(<a href='http://daringfireball.net/projects/markdown/basics'>"
            "Markdown formatted"
            "</a>)"),
    )
    featured = models.BooleanField(help_text="Promote to the front page")
    always_featured = models.BooleanField(
        help_text="Always promote to the top of lists.", default=False)
    dedicated_partner_page = models.BooleanField(
        help_text="Does this partner have it's own dedicated page?")
    technology = models.ManyToManyField(Technology,
                                        related_name="partners",
                                        blank=True,
                                        null=True)
    programme = models.ManyToManyField(Programme,
                                       related_name="partners",
                                       blank=True,
                                       null=True)
    service_offered = models.ManyToManyField(ServiceOffered,
                                             related_name="partners",
                                             blank=True,
                                             null=True)
    partner_type = models.ManyToManyField(
        PartnerType,
        related_name="partners",
        blank=True,
        null=True,
        help_text=("test"),
    )
    notes = models.TextField(blank=True,
                             help_text="Private, for internal Canonical use")

    def quotes(self):
        return serializers.serialize("python", self.quote_set.all())

    def links(self):
        return serializers.serialize("python", self.link_set.all())

    def insights_tags(self):
        return serializers.serialize("python", self.insightstag_set.all())

    tags_label = models.CharField(
        max_length=200,
        blank=True,
        help_text="The displayed name for the tags list",
    )

    def tags(self):
        return serializers.serialize("python", self.tag_set.all())

    def texts(self):
        return serializers.serialize("python", self.text_set.all())
Beispiel #26
0
class Todo(ValidateOnSaveMixin, models.Model):
    STATES = (
        (INBOX, 'Inbox'),
        (NEXT, 'Next'),
        (WAITING, 'Waiting'),
        (SOMEDAY, 'Someday')
    )

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    title = models.CharField(max_length=255, null=False, blank=False,
                             validators=[MinLengthValidator(1), MaxLengthValidator(255)])
    is_done = models.BooleanField(null=False, default=False)
    state = models.CharField(max_length=7, choices=STATES, default=INBOX)
    priority_order = models.IntegerField(default=0)
    is_archived = models.BooleanField(null=False, default=False)

    objects = TodoManager()
    archived = ArchivedTodoManager()

    def __init__(self, *args, **kwargs):
        super(Todo, self).__init__(*args, **kwargs)
        self._original_state = self.__dict__

    def prioritize(self, priority_order):
        if priority_order is self.priority_order:
            return

        # TODO: replace with one update query
        query = Todo.objects.filter(
            ~Q(pk=self.id),
            Q(state=self.state),
        )
        if priority_order < self.priority_order:
            query = query.filter(
                Q(priority_order__gte=priority_order),
                Q(priority_order__lt=self.priority_order)
            ).order_by('priority_order')

            for todo in query:
                todo.priority_order += 1
                todo.save()

        else:
            query = query.filter(
                Q(priority_order__lte=priority_order),
                Q(priority_order__gt=self.priority_order)
            ).order_by('priority_order')

            for todo in query:
                todo.priority_order -= 1
                todo.save()

        self.priority_order = priority_order
        self.save()

    def save(self, *args, **kwargs):
        if self._did_state_changed():
            self._change_priority_of_remaining_todos()

        if self._should_change_priority_order():
            # When the state has changed or if the todo is newly created
            # we need to assign a new prioritization to self
            try:
                self.priority_order = Todo.get_next_priority_order(self.state)
            except:
                pass

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

    def delete(self, using=None, keep_parents=False):
        self._change_priority_of_remaining_todos()
        super(Todo, self).delete(using, keep_parents)

    def _change_priority_of_remaining_todos(self):
        # If the state has changed we need to update the
        # prioritization of the remaining todo in the previous state
        query = Todo.objects.filter(
            ~Q(pk=self.id),
            Q(state=self._original_state.get('state')),
            Q(priority_order__gt=self.priority_order)
        ).order_by('priority_order')

        for todo in query:
            todo.priority_order -= 1
            todo.save()

    def _did_state_changed(self):
        return self._original_state.get('state') != self.state

    def _should_change_priority_order(self):
        return self._state.adding or self._did_state_changed()

    @classmethod
    def from_db(cls, db, field_names, values):
        instance = super(Todo, cls).from_db(db, field_names, values)

        # customization to store the original field values on the instance
        instance._original_state = dict(zip(field_names, values))
        return instance

    @staticmethod
    def get_next_priority_order(state):
        return Todo.objects.filter(state=state).order_by('-priority_order').first().priority_order + 1
Beispiel #27
0
class Product(models.Model):
    shop = models.ForeignKey(Shop)
    title = models.CharField(_(u"שם המוצר"), max_length=200)
    description = models.TextField(_(u"תאור"),
                                   blank=True,
                                   null=True,
                                   validators=[MaxLengthValidator(MAX_TEXT)])
    item_price = models.PositiveIntegerField(_(u"מחיר"), default=0)
    number_of_abailabale_items = models.PositiveIntegerField(_(u"כמה במלאי"),
                                                             default=0)
    number_of_selected_items = models.PositiveIntegerField(default=0)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    end_of_sale_at = models.DateTimeField(_(u"סיום המכירה"),
                                          null=True,
                                          blank=True,
                                          default=None)
    end_of_use_at = models.DateTimeField(_(u"תקף עד"),
                                         null=True,
                                         blank=True,
                                         default=None)

    def __unicode__(self):
        return "id {}:{} {}".format(self.id, self.title, self.item_price)

    def get_absolute_url(self):
        return (reverse('memecache:product_details',
                        kwargs={'pk': str(self.id)}))

    def can_buy(self):
        if self.end_of_sale_at:
            if self.end_of_sale_at < timezone.now():
                return False
        return self.can_use()

    def can_use(self):
        if self.end_of_use_at:
            if self.end_of_use_at < timezone.now():
                return False
        return True

    def get_number_of_availabale_items(self):
        if not self.can_buy():
            return 0

        return self.number_of_abailabale_items

    def get_number_of_selected_items(self):
        if not self.can_buy():
            return 0

        return (self.number_of_selected_items)

    def select_items(self, number_of_items_diff):
        if number_of_items_diff <= self.get_number_of_availabale_items():
            self.number_of_abailabale_items -= number_of_items_diff
            self.number_of_selected_items += number_of_items_diff
            self.save()

    def bought_items(self, number_of_sold_items):
        if self.get_number_of_selected_items() >= number_of_sold_items:
            self.number_of_selected_items -= number_of_sold_items
            self.save()

    def print_content(self):
        print 'product name', self.title, 'item_price', self.item_price, 'shop', self.shop.title, 'description', self.description, 'availabale items:', self.number_of_abailabale_items, 'selected', self.number_of_selected_items, 'sold', self.itemvoucher_set.filter(
            used=False).count(), 'used', self.itemvoucher_set.filter(
                used=True).count()
        print 'created_at', self.created_at, 'updated_at', self.updated_at, 'end_of_sale_at', self.end_of_sale_at, 'end_of_use_at', self.end_of_use_at

        for procduct_selection in self.productselection_set.all():
            print procduct_selection.print_content()

        for item in self.itemvoucher_set.all():
            item.print_content()
Beispiel #28
0
class Responsibility(models.Model):
    description = models.TextField(validators=[MaxLengthValidator(100)])
Beispiel #29
0
class Customer(
        core_models.UuidMixin,
        core_models.NameMixin,
        core_models.DescendantMixin,
        quotas_models.ExtendableQuotaModelMixin,
        PermissionMixin,
        VATMixin,
        StructureLoggableMixin,
        ImageModelMixin,
        TimeStampedModel,
        CoordinatesMixin,
        StructureModel,
):
    class Permissions:
        customer_path = 'self'
        project_path = 'projects'

    native_name = models.CharField(max_length=160, default='', blank=True)
    abbreviation = models.CharField(max_length=12, blank=True)
    contact_details = models.TextField(blank=True,
                                       validators=[MaxLengthValidator(500)])

    agreement_number = models.PositiveIntegerField(null=True, blank=True)
    sponsor_number = models.PositiveIntegerField(
        null=True,
        blank=True,
        help_text=_('External ID of the sponsor covering the costs'),
    )

    email = models.EmailField(_('email address'), max_length=75, blank=True)
    phone_number = models.CharField(_('phone number'),
                                    max_length=255,
                                    blank=True)
    access_subnets = models.TextField(
        validators=[validate_cidr_list],
        blank=True,
        default='',
        help_text=_(
            'Enter a comma separated list of IPv4 or IPv6 '
            'CIDR addresses from where connection to self-service is allowed.'
        ),
    )
    backend_id = models.CharField(
        max_length=255,
        blank=True,
        help_text=_('Organization identifier in another application.'),
    )
    registration_code = models.CharField(max_length=160,
                                         default='',
                                         blank=True)
    homepage = models.URLField(max_length=255, blank=True)
    domain = models.CharField(max_length=255, blank=True)

    address = models.CharField(blank=True, max_length=300)
    postal = models.CharField(blank=True, max_length=20)
    bank_name = models.CharField(blank=True, max_length=150)
    bank_account = models.CharField(blank=True, max_length=50)
    accounting_start_date = models.DateTimeField(_('Start date of accounting'),
                                                 default=timezone.now)
    default_tax_percent = models.DecimalField(
        default=0,
        max_digits=4,
        decimal_places=2,
        validators=[MinValueValidator(0),
                    MaxValueValidator(100)],
    )
    blocked = models.BooleanField(default=False)
    division = models.ForeignKey('Division',
                                 null=True,
                                 blank=True,
                                 on_delete=models.SET_NULL)
    tracker = FieldTracker()

    class Meta:
        verbose_name = _('organization')
        ordering = ('name', )

    GLOBAL_COUNT_QUOTA_NAME = 'nc_global_customer_count'

    class Quotas(quotas_models.QuotaModelMixin.Quotas):
        enable_fields_caching = False
        nc_project_count = quotas_fields.CounterQuotaField(
            target_models=lambda: [Project],
            path_to_scope='customer',
        )
        nc_service_count = quotas_fields.CounterQuotaField(
            target_models=lambda: Service.get_all_models(),
            path_to_scope='customer',
        )
        nc_user_count = quotas_fields.QuotaField()
        nc_resource_count = quotas_fields.CounterQuotaField(
            target_models=lambda: ResourceMixin.get_all_models(),
            path_to_scope='project.customer',
        )
        nc_app_count = quotas_fields.CounterQuotaField(
            target_models=lambda: ApplicationMixin.get_all_models(),
            path_to_scope='project.customer',
        )
        nc_vm_count = quotas_fields.CounterQuotaField(
            target_models=lambda: VirtualMachine.get_all_models(),
            path_to_scope='project.customer',
        )
        nc_private_cloud_count = quotas_fields.CounterQuotaField(
            target_models=lambda: PrivateCloud.get_all_models(),
            path_to_scope='project.customer',
        )
        nc_storage_count = quotas_fields.CounterQuotaField(
            target_models=lambda: Storage.get_all_models(),
            path_to_scope='project.customer',
        )
        nc_volume_size = quotas_fields.TotalQuotaField(
            target_models=lambda: Volume.get_all_models(),
            path_to_scope='customer',
            target_field='size',
        )
        nc_snapshot_size = quotas_fields.TotalQuotaField(
            target_models=lambda: Snapshot.get_all_models(),
            path_to_scope='customer',
            target_field='size',
        )

    def get_log_fields(self):
        return ('uuid', 'name', 'abbreviation', 'contact_details')

    def get_owners(self):
        return get_user_model().objects.filter(
            customerpermission__customer=self,
            customerpermission__is_active=True,
            customerpermission__role=CustomerRole.OWNER,
        )

    def get_support_users(self):
        return get_user_model().objects.filter(
            customerpermission__customer=self,
            customerpermission__is_active=True,
            customerpermission__role=CustomerRole.SUPPORT,
        )

    def get_users(self):
        """ Return all connected to customer users """
        return (get_user_model().objects.filter(
            Q(customerpermission__customer=self,
              customerpermission__is_active=True)
            | Q(
                projectpermission__project__customer=self,
                projectpermission__is_active=True,
            )).distinct().order_by('username'))

    def can_user_update_quotas(self, user):
        return user.is_staff

    def can_manage_role(self, user, role=None, timestamp=False):
        """
        Checks whether user can grant/update/revoke customer permissions.
        `timestamp` can have following values:
            - False - check whether user can manage permissions at the moment.
            - None - check whether user can permanently manage permissions.
            - Datetime object - check whether user will be able to manage permissions at specific timestamp.
        """
        return user.is_staff or (
            self.has_user(user, CustomerRole.OWNER, timestamp)
            and settings.WALDUR_CORE['OWNERS_CAN_MANAGE_OWNERS'])

    def get_children(self):
        return itertools.chain.from_iterable(
            m.objects.filter(customer=self)
            for m in [Project] + Service.get_all_models())

    def is_billable(self):
        return timezone.now() >= self.accounting_start_date

    @classmethod
    def get_permitted_objects(cls, user):
        if user.is_staff or user.is_support:
            return cls.objects.all()
        else:
            return cls.objects.filter(
                permissions__user=user,
                permissions__role=CustomerRole.OWNER,
                permissions__is_active=True,
            )

    def get_display_name(self):
        if self.abbreviation:
            return self.abbreviation
        if self.domain:
            return '{name} ({domain})'.format(name=self.name,
                                              domain=self.domain)
        return self.name

    def delete(self, *args, **kwargs):
        """Delete customers' projects if they all mark as 'removed'."""
        if not self.projects.count():
            for project in Project.structure_objects.filter(customer=self):
                project.delete(soft=False)

        return super(Customer, self).delete(*args, **kwargs)

    def __str__(self):
        if self.abbreviation:
            return '%(name)s (%(abbreviation)s)' % {
                'name': self.name,
                'abbreviation': self.abbreviation,
            }
        else:
            return self.name
Beispiel #30
0
class GvOrgAbstract(GvAdminAbstract):
    '''
    Gemeinsame Basisklasse für gvOrgUnit und gvOrganization
    Wird benötigt, weil gvOrganization nicht das Feld 'ou' erbt (weil es mandatory wäre).
    (db_column setzt eineige Felder auf Lowercase zur Vereinfachung von Abfragen in Postgresql.)
    '''
    class Meta:
        abstract = True

    gvouid = models.CharField(max_length=32,
        unique=True,
        verbose_name='gvOuId',
        validators=[RegexValidator(regex=r'^[A-Z:]{10,10}.*', message='OuId erlaubt Kleinbuchstaben erst ab Position 11')],
        help_text='Syntax: gvOuId::= Landeskennung ":" ID; ID::= "VKZ:" VKZ | Org-Id  (z.B. AT:VKZ:GGA1234, AT:L9:9876)',)
    gvouvkz = models.CharField(max_length=79,
        unique=True,
        verbose_name='Verwaltungskennz (gvOuVKZ)',
        validators=[RegexValidator(regex=r'^[A-Z:]{2,2}.*', message='VKZ erlaubt Kleinbuchstaben erst ab Position 3'),
                    MaxLengthValidator(32, '"gvOuVKZ " Limit: 32 char')],
        help_text='Organisationskennzeichen (OKZ) gemäß der Spezifikation [VKZ]. Das Organisationskennzeichen ist für '
                  'die Verwendung auf Ausdrucken, als Suchbegriff bzw. zur Anzeige vorgesehen. Das OKZ enthält Semantik'
                  ' und ist nur für österreichische Organisationen definiert. Für Referenzen in elektronischen '
                  'Datenbeständen soll dieses Kennzeichen NICHT verwendet werden, sondern ausschließlich die gvOuId. '
                  'Das VKZ kann aufgrund von Namensänderungen angepasst werden müssen. (z.B. BMEIA statt BMAA für das '
                  'Außenministerium) 
(z.B. GGA-12345)')
    gvouidparent = models.CharField(max_length=32,
        default='',
        verbose_name='Übergeordnete OE; (gvOuIdParent)',
        db_column='gvouid_parent',
        null=True, blank=True,
        help_text='gvOuId der übergeordneten OEs (kein dn!)')  # Foreign Key hier nicht implementiert
    gvOuCn = models.CharField(max_length=1024,
        verbose_name='Gesamtbezeichnung (gvOuCn)',
        db_column='gvoucn',
        help_text='Gesamtbezeichnung der Organisationseinheit für die Anschrift ohne Adressteil. (Bundesministerium für Inneres Sektion IV / Abt.ITMS / Ref.NIK)', )
    gvNotValidBefore = models.CharField(max_length=10,
        verbose_name='gültig ab',
        db_column='gvnotvalidbefore',
        null=True, blank=True,
        help_text='JJJJ-MM-TT',)
    gvNotValidAfter = models.CharField(max_length=10,
        verbose_name='gültig bis',
        db_column='gvnotvalidafter',
        null=True, blank=True,
        help_text='Format JJJJ-MM-TT',)
    gvImageRef = models.CharField(max_length=250, default='', null=True, blank=True,)
    gvLegalSuccessor = models.CharField(max_length=250, default='', null=True, blank=True,)
    gvOtherID = models.CharField(max_length=250, default='', null=True, blank=True,)
    gvPhysicalAddress = models.CharField(max_length=250, default='', null=True, blank=True,)
    gvSortkey = models.CharField(max_length=250, default='', null=True, blank=True,)
    gvWebAddress = models.CharField(max_length=250, default='', null=True, blank=True,)
    gvouid_upper = models.CharField(max_length=250, default='', unique=True, null=True, blank=True,)
    gvouvkz_upper = models.CharField(max_length=250, default='', unique=True, null=True, blank=True,)

    c = models.CharField(max_length=250,default='AT', null=True, blank=True,)
    cn = models.CharField(max_length=1024,
        verbose_name='Bezeichnung (cn)',
        help_text='Bezeichnung der Organisationseinheit (ausgeschrieben). (Abt. ITMS/Ref. NIK - 
Referat nationale und internationale Koordination)',
    )
    co = models.CharField(max_length=250, default='', null=True, blank=True,)
    description = models.TextField(max_length=1024,
        null=True, blank=True,
        help_text='Beschreibung',)
    facsimileTelephoneNumber = models.CharField(max_length=250, default='', null=True, blank=True,)
    l = models.CharField(max_length=123,
        verbose_name='Ort (l)',
        null=True, blank=True,
        help_text='Ort',
        validators=[MaxLengthValidator(64, '"l" Limit: 64 char')],)
    mail = models.CharField(max_length=256,
        null=True, blank=True,
        help_text='RFC 822 [RFC882] E-Mail-Adresse 
([email protected])',)
    ou = models.CharField(max_length=250, default='', null=True, blank=True,)
    postalAddress = models.CharField(max_length=250, default='', null=True, blank=True,)
    postalCode = models.CharField(max_length=250, default='', null=True, blank=True,)
    postOfficeBox = models.CharField(max_length=250, default='', null=True, blank=True,)
    street = models.CharField(max_length=250, default='', null=True, blank=True,)
    telephoneNumber = models.CharField(max_length=250, default='', null=True, blank=True,)

    def save(self, *args, **kwargs):
        self.gvouid_upper = self.gvouid.upper()
        self.gvouvkz_upper = self.gvouvkz.upper()
        super(GvOrgAbstract, self).save(*args, **kwargs)

    # attributes defined in LDAP-gvat_2-5-1_20171222.pdf
    @staticmethod
    def defined_attr() -> list:
        combined_list = GvAdminAbstract().defined_attr()    # cannot super() in static method
        combined_list += [
            'cn',
            'co',
            'description',
            'facsimileTelephoneNumber',
            'gvImageRef',
            'gvLegalSuccessor',
            'gvNotValidAfter',
            'gvNotValidBefore',
            'gvOtherID',
            'gvOuCn',
            'gvouid',
            'gvouidparent',
            'gvouvkz',
            'gvPhysicalAddress',
            'gvScope',
            'gvSortkey',
            'gvSource',
            'gvStatus',
            'gvWebAddress',
            'l',
            'mail',
            'postalAddress',
            'postalCode',
            'postOfficeBox',
            'street',
            'telephoneNumber',
        ]
        return combined_list

    def __str__(self):
        return f"{self.gvouid} {self.cn}"

    def __repr__(self):
        return self.ldap_dn