class ReferencedListFieldNonFullTestResource(resources.MongoEngineResource):
    referencedlist = fields.ReferencedListField(of='test_project.test_app.api.resources.PersonResource', attribute='referencedlist', full=False, null=True)

    class Meta:
        queryset = documents.ReferencedListFieldTest.objects.all()
        allowed_methods = ('get', 'post', 'put', 'patch', 'delete')
        authorization = tastypie_authorization.Authorization()
예제 #2
0
class LotteryResource(BaseResource):
    users = fields.ReferencedListField(of='apis.base.resources.UserResource',
                                       attribute='users',
                                       full=True,
                                       null=True)
    paper = fields.ReferenceField(to='apis.base.resources.PaperResource',
                                  attribute='paper',
                                  full=True,
                                  null=True)

    class Meta:
        queryset = Lottery.objects(is_online=True)
        allowed_methods = ('get', )
        authentication = UserAuthentication()
        authorization = Authorization()
        filtering = {'period': ALL}

    def prepend_urls(self):
        return [
            url(r"^(?P<resource_name>%s)/yesterday%s$" % (self._meta.resource_name, trailing_slash()), \
                self.wrap_view('yesterday'), name="api_yesterday"),
        ]

    def yesterday(self, request, **kwargs):
        today = datetime.utcnow().replace(hour=0,
                                          minute=0,
                                          second=0,
                                          microsecond=0)
        yesterday = today - timedelta(days=1)
        params = dict(request.GET.dict().items() + {
            'period__gte': yesterday,
            'period__lt': today
        }.items())
        return redirect(u'{}/api/v1/lottery/?{}'.format(
            SUB_DOMAIN or '', urlencode(params)))
예제 #3
0
class InvoiceBaseGroupResource(TenantResource):
    quotation = fields.ReferenceField(
        to='invoicing.api.resources.QuotationResource',
        attribute='quotation',
        readonly=True,
        null=True,
        help_text=HELP_TEXT['invoice_base_group']['quotation'])
    purchase_order = fields.ReferenceField(
        to='invoicing.api.resources.PurchaseOrderResource',
        attribute='purchase_order',
        readonly=True,
        null=True,
        help_text=HELP_TEXT['invoice_base_group']['purchase_order'])
    down_payment_invoices = fields.ReferencedListField(
        of='invoicing.api.resources.DownPaymentInvoiceResource',
        attribute='down_payment_invoices',
        readonly=True,
        null=True,
        help_text=HELP_TEXT['invoice_base_group']['down_payment_invoices'])
    invoice = fields.ReferenceField(
        to='invoicing.api.resources.InvoiceResource',
        attribute='invoice',
        readonly=True,
        null=True,
        help_text=HELP_TEXT['invoice_base_group']['invoice'])
    invoices_cancelled = fields.ReferencedListField(
        of='invoicing.api.resources.InvoiceResource',
        attribute='invoices_cancelled',
        readonly=True,
        null=True,
        help_text=HELP_TEXT['invoice_base_group']['invoices_cancelled'])
    credit_notes = fields.ReferencedListField(
        of='invoicing.api.resources.CreditNoteResource',
        attribute='credit_notes',
        readonly=True,
        null=True,
        help_text=HELP_TEXT['invoice_base_group']['credit_notes'])

    class Meta(TenantResource.Meta):
        resource_name = 'invoice_base_group'
        object_class = InvoiceBaseGroup
        list_allowed_methods = ('get', )
        detail_allowed_methods = ('get', )
        excludes = ('tenant', )
class ContactGroupResource(resources.MongoEngineResource):
    contacts = fields.ReferencedListField(
        of='test_project.test_app.api.resources.ContactResource',
        attribute='contacts',
        null=True)

    class Meta(object):
        queryset = documents.ContactGroup.objects.all()
        allowed_methods = ('get', 'post', 'put', 'patch', 'delete')
        authorization = tastypie_authorization.Authorization()
예제 #5
0
class PackageResource(resources.MongoEngineResource):
    functions = fields.ReferencedListField(
        of='netlambda.resources.FunctionResource',
        attribute='functions',
        full=True,
        null=True)

    class Meta:
        object_class = models.Package
        allowed_methods = ('get')
        resource_name = 'pack'
예제 #6
0
class WorkspaceResource(mongoresources.MongoEngineResource):
    user = fields.ReferenceField(to='lisa.server.web.weblisa.api.UserResource',
                                 attribute='user')
    widgets = fields.ReferencedListField(
        of='lisa.server.web.interface.api.WidgetByUserResource',
        attribute='widgets',
        full=True,
        null=True,
        help_text='List of widgets')

    class Meta:
        queryset = Workspace.objects.all()
        allowed_methods = ('get', 'post', 'put', 'patch')
        authorization = authorization.Authorization()
예제 #7
0
class QuizResource(BaseResource):
    products = fields.ReferencedListField(
        of='apis.base.resources.ProductResource',
        attribute='products',
        full=True,
        null=True)

    class Meta:
        queryset = Quiz.objects()
        allowed_methods = ('get', )
        authentication = UserAuthentication()
        authorization = Authorization()
        excludes = ('resource_uri', )
        ordering = ('created_at', )
예제 #8
0
class InvoiceResource(InvoiceBaseResource):
    state = base_fields.CharField(
        attribute='state',
        readonly=True,
        help_text=HELP_TEXT['invoice']['state']
    )
    paid = base_fields.DecimalField(
        attribute='paid',
        readonly=True,
        help_text=HELP_TEXT['invoice']['paid']
    )
    balance = base_fields.DecimalField(
        attribute='balance',
        readonly=True,
        help_text=HELP_TEXT['invoice']['balance']
    )
    has_temporary_reference = base_fields.BooleanField(
        attribute='has_temporary_reference',
        readonly=True,
        help_text=HELP_TEXT['invoice']['has_temporary_reference']
    )

    related_to = fields.ReferenceField(
        to='invoicing.api.resources.QuotationResource',
        attribute='related_to',
        readonly=True,
        null=True,
        help_text=HELP_TEXT['invoice']['related_to']
    )
    payments = fields.ReferencedListField(
        of='invoicing.api.resources.PaymentResource',
        attribute='payments',
        readonly=True,
        null=True,
        blank=True,
        help_text=HELP_TEXT['invoice']['payments']
    )

    class Meta(InvoiceBaseResource.Meta):
        queryset = Invoice.objects.all()
        detail_specific_methods = ('cancel', 'mark_as_registered')

    def prepend_urls(self):
        """Add urls for resources actions."""
        urls = super(InvoiceResource, self).prepend_urls()
        urls.extend((
            url(r'^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/cancel%s$' % (self._meta.resource_name, trailing_slash()), self.wrap_view('invoice_cancel'), name='api_invoice_cancel'),
        ))
        return urls

    def invoice_cancel(self, request, **kwargs):
        """Cancel the invoice and returns the associated credit note."""
        from invoicing.api.resources.credit_note import CreditNoteResource
        self.method_check(request, allowed=['put'])
        self.is_authenticated(request)
        self.throttle_check(request)

        try:
            bundle = self.build_bundle(request=request)
            obj = self.cached_obj_get(bundle=bundle, **self.remove_api_resource_names(kwargs))
        except ObjectDoesNotExist:
            return http.HttpNotFound()

        try:
            credit_note = obj.cancel(request.vosae_user)
            invoicing_signals.post_cancel_invoice.send(obj.__class__, issuer=request.vosae_user, document=obj, credit_note=credit_note)
            credit_note_resource = CreditNoteResource()
            credit_note_resource_bundle = credit_note_resource.build_bundle(obj=credit_note, request=request)
        except NotCancelableInvoice as e:
            raise BadRequest(e)

        self.log_throttled_access(request)

        to_be_serialized = {
            'credit_note_uri': credit_note_resource.get_resource_uri(credit_note_resource_bundle)
        }
        to_be_serialized = self.alter_list_data_to_serialize(request, to_be_serialized)
        return self.create_response(request, to_be_serialized)

    def dehydrate_related_to(self, bundle):
        from invoicing.api.resources import QuotationResource, PurchaseOrderResource
        try:
            if bundle.obj.related_to.is_quotation():
                resource = QuotationResource()
            elif bundle.obj.related_to.is_purchase_order():
                resource = PurchaseOrderResource()
            resource_bundle = resource.build_bundle(obj=bundle.obj.related_to, request=bundle.request)
            return resource.get_resource_uri(resource_bundle)
        except:
            return
예제 #9
0
class InvoiceBaseResource(NotificationAwareResourceMixin, TenantResource,
                          VosaeIMEXMixinResource):
    reference = base_fields.CharField(
        attribute='reference',
        readonly=True,
        help_text=HELP_TEXT['invoicebase']['reference'])
    total = base_fields.DecimalField(
        attribute='total',
        readonly=True,
        help_text=HELP_TEXT['invoicebase']['total'])
    amount = base_fields.DecimalField(
        attribute='amount',
        readonly=True,
        help_text=HELP_TEXT['invoicebase']['amount'])
    account_type = base_fields.CharField(
        attribute='account_type',
        help_text=HELP_TEXT['invoicebase']['account_type'])

    issuer = fields.ReferenceField(
        to='core.api.resources.VosaeUserResource',
        attribute='issuer',
        readonly=True,
        help_text=HELP_TEXT['invoicebase']['issuer'])
    organization = fields.ReferenceField(
        to='contacts.api.resources.OrganizationResource',
        attribute='organization',
        readonly=True,
        null=True,
        help_text=HELP_TEXT['invoicebase']['organization'])
    contact = fields.ReferenceField(
        to='contacts.api.resources.ContactResource',
        attribute='contact',
        readonly=True,
        null=True,
        help_text=HELP_TEXT['invoicebase']['contact'])
    history = fields.EmbeddedListField(
        of='invoicing.api.resources.InvoiceHistoryEntryResource',
        attribute='history',
        readonly=True,
        full=True,
        null=True,
        blank=True,
        help_text=HELP_TEXT['invoicebase']['history'])
    notes = fields.EmbeddedListField(
        of='invoicing.api.resources.InvoiceNoteResource',
        attribute='notes',
        full=True,
        null=True,
        blank=True,
        help_text=HELP_TEXT['invoicebase']['notes'])
    group = fields.ReferenceField(
        to='invoicing.api.resources.InvoiceBaseGroupResource',
        attribute='group',
        readonly=True,
        help_text=HELP_TEXT['invoicebase']['group'])
    attachments = fields.ReferencedListField(
        of='core.api.resources.VosaeFileResource',
        attribute='attachments',
        null=True,
        blank=True,
        help_text=HELP_TEXT['invoicebase']['attachments'])

    class Meta(TenantResource.Meta):
        excludes = ('tenant', 'base_type', 'subscribers')
        filtering = {
            'state': ('exact', 'in'),
            'contact': ('exact', ),
            'organization': ('exact', ),
            'account_type': ('exact', ),
            'reference': ('contains', )
        }

        available_imex_serializers = (invoicing_imex.PDFSerializer, )

    def prepend_urls(self):
        """Add urls for resources actions."""
        urls = super(InvoiceBaseResource, self).prepend_urls()
        urls.extend(VosaeIMEXMixinResource.prepend_urls(self))
        urls.extend((
            url(r'^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/send/mail%s$' %
                (self._meta.resource_name, trailing_slash()),
                self.wrap_view('send_by_mail'),
                name='api_invoicebase_send_by_mail'),
            url(r'^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/mark_as_(?P<invoicebase_state>(%s))%s$'
                % (self._meta.resource_name, '|'.join(
                    [k.lower() for k in MARK_AS_STATES]), trailing_slash()),
                self.wrap_view('mark_as_state'),
                name='api_invoicebase_mark_as_state'),
            url(r'^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/generate_pdf%s$' %
                (self._meta.resource_name, trailing_slash()),
                self.wrap_view('generate_pdf'),
                name='api_invoicebase_generate_pdf'),
        ))
        return urls

    @classmethod
    def post_save(self, sender, resource, bundle, created, **kwargs):
        """
        Post save API hook handler

        - Add timeline and notification entries
        """
        # Add timeline and notification entries
        invoicebase_saved_task.delay(bundle.request.vosae_user, bundle.obj,
                                     created)

    def obj_delete(self, bundle, **kwargs):
        """Raises a BadRequest if the :class:`~invoicing.models.InvoiceBase` is not in a deletable state"""
        try:
            super(InvoiceBaseResource, self).obj_delete(bundle, **kwargs)
        except NotDeletableInvoice as e:
            raise BadRequest(e)

    def do_export(self, request, serializer, export_objects):
        """Export"""
        if len(export_objects) is not 1:
            raise BadRequest('PDF export can only be done on a single item.')
        return serializer.serialize(export_objects[0]), None

    def send_by_mail(self, request, **kwargs):
        """Send an InvoiceBase by mail."""
        self.method_check(request, allowed=['post'])
        self.is_authenticated(request)
        self.throttle_check(request)

        try:
            bundle = self.build_bundle(request=request)
            obj = self.cached_obj_get(bundle=bundle,
                                      **self.remove_api_resource_names(kwargs))
        except ObjectDoesNotExist:
            return http.HttpNotFound()

        try:
            email_data = self.deserialize(request,
                                          request.body,
                                          format=request.META.get(
                                              'CONTENT_TYPE',
                                              'application/json'))
            subject = email_data.get('subject')
            message = email_data.get('message')
            to = email_data.get('to')
            cc = email_data.get('cc', [])
            bcc = email_data.get('bcc', [])
            assert isinstance(to, list) and isinstance(
                cc, list) and isinstance(bcc, list)
        except:
            raise BadRequest('Invalid email parameters.')

        try:
            obj.send_by_mail(subject, message, to, cc, bcc, request.vosae_user)
        except:
            raise BadRequest('Can\'t send email. Verify parameters.')

        self.log_throttled_access(request)

        to_be_serialized = {}
        to_be_serialized = self.alter_list_data_to_serialize(
            request, to_be_serialized)
        return self.create_response(request, to_be_serialized)

    def mark_as_state(self, request, invoicebase_state, **kwargs):
        """Set state for an InvoiceBase."""
        self.method_check(request, allowed=['put'])
        self.is_authenticated(request)
        self.throttle_check(request)

        try:
            bundle = self.build_bundle(request=request)
            obj = self.cached_obj_get(bundle=bundle,
                                      **self.remove_api_resource_names(kwargs))
        except ObjectDoesNotExist:
            return http.HttpNotFound()

        try:
            previous_state, new_state = obj.set_state(
                invoicebase_state.upper(), issuer=request.vosae_user)
            invoicing_signals.post_client_changed_invoice_state.send(
                obj.__class__,
                issuer=request.vosae_user,
                document=obj,
                previous_state=previous_state)
        except (obj.InvalidState, InvalidInvoiceBaseState) as e:
            raise BadRequest(e)

        self.log_throttled_access(request)

        return http.HttpNoContent()
        # May need to use this with ember (check if always_return_data)
        # to_be_serialized = ''
        # to_be_serialized = self.alter_list_data_to_serialize(request, to_be_serialized)
        # return self.create_response(request, to_be_serialized)

    def generate_pdf(self, request, **kwargs):
        """Generate a PDF"""
        self.method_check(request, allowed=['get'])
        self.is_authenticated(request)
        self.throttle_check(request)

        try:
            bundle = self.build_bundle(request=request)
            obj = self.cached_obj_get(bundle=bundle,
                                      **self.remove_api_resource_names(kwargs))
        except ObjectDoesNotExist:
            return http.HttpNotFound()

        try:
            language = request.META.get('HTTP_X_REPORT_LANGUAGE', None)
            if language is not None:
                assert language in [k[0] for k in settings.LANGUAGES]
        except:
            raise BadRequest('Invalid language parameters.')

        try:
            pdf = obj.get_pdf(issuer=request.vosae_user, language=language)
            pdf_resource = VosaeFileResource()
            pdf_resource_bundle = pdf_resource.build_bundle(obj=pdf,
                                                            request=request)
        except Exception, e:
            print e
            raise BadRequest('Can\'t generate PDF. Verify parameters.')

        self.log_throttled_access(request)

        pdf_resource_bundle = pdf_resource.full_dehydrate(pdf_resource_bundle)
        pdf_resource_bundle = pdf_resource.alter_detail_data_to_serialize(
            request, pdf_resource_bundle)
        return pdf_resource.create_response(request, pdf_resource_bundle)
예제 #10
0
class PaperResource(BaseResource):
    quizes = fields.ReferencedListField(of='apis.base.resources.QuizResource',
                                        attribute='quizes',
                                        full=True,
                                        null=True)

    class Meta:
        queryset = Paper.objects(is_online=True)
        allowed_methods = ('get', )
        authentication = UserAuthentication()
        authorization = Authorization()
        excludes = ('resource_uri', )
        filtering = {'period': ALL}
        ordering = ('period', )

    def prepend_urls(self):
        return [
            url(r"^(?P<resource_name>%s)/current%s$" % (self._meta.resource_name, trailing_slash()), \
                self.wrap_view('current'), name="api_current"),
            url(r"^(?P<resource_name>%s)/history%s$" % (self._meta.resource_name, trailing_slash()), \
                self.wrap_view('history'), name="api_history"),
            url(r"^(?P<resource_name>%s)/yesterday%s$" % (self._meta.resource_name, trailing_slash()), \
                self.wrap_view('yesterday'), name="api_yesterday"),
        ]

    def current(self, request, **kwargs):
        today = datetime.utcnow().replace(hour=0,
                                          minute=0,
                                          second=0,
                                          microsecond=0)
        tomorrow = today + timedelta(days=1)
        params = dict(request.GET.dict().items() + {
            'period__gte': today,
            'period__lt': tomorrow
        }.items())
        return redirect(u'{}/api/v1/paper/?{}'.format(SUB_DOMAIN or '',
                                                      urlencode(params)))

    def yesterday(self, request, **kwargs):
        today = datetime.utcnow().replace(hour=0,
                                          minute=0,
                                          second=0,
                                          microsecond=0)
        yesterday = today - timedelta(days=1)
        params = dict(request.GET.dict().items() + {
            'period__gte': yesterday,
            'period__lt': today
        }.items())
        return redirect(u'{}/api/v1/paper/history/?{}'.format(
            SUB_DOMAIN or '', urlencode(params)))

    def history(self, request, **kwargs):
        today = datetime.utcnow().replace(hour=0,
                                          minute=0,
                                          second=0,
                                          microsecond=0)
        param_dict = request.GET.dict()
        params = dict(param_dict.items() + {'period__lt': today}.items()) \
            if 'period__lt' not in param_dict or datetime.strptime(param_dict['period__lt'], '%Y-%m-%d %H:%M:%S') > today else param_dict
        papers_url = u'http://{}/api/v1/paper/?{}'.format(
            request.META['HTTP_HOST'], urlencode(params))
        earliest_paper = Paper.objects().order_by('period').first()
        earliest = earliest_paper.period if earliest_paper else None

        if not request.user.is_authenticated():
            res = requests.get(papers_url).json()
            for data in res['objects']:
                paper_id = data['id']
                paper_answers = data.get('answers', {})
                paper = Paper.objects(id=paper_id).first()
                if not paper:
                    continue

                for quiz in data.get('quizes', []):
                    for prod in quiz.get('products', []):
                        if quiz['id'] in paper_answers \
                            and prod['id'] in paper_answers[quiz['id']]:
                            prod['score'] = paper_answers[quiz['id']][
                                prod['id']]

                if 'answers' in data:
                    del data['answers']

            res['meta']['earliest'] = earliest
            return self.create_response(request, res)

        else:
            res = requests.get(papers_url).json()
            for data in res['objects']:
                paper_id = data['id']
                paper = Paper.objects(id=paper_id).first()
                if not paper:
                    continue

                mark = Mark.objects(paper=paper, user=request.user).first()
                paper_answers = data.get('answers', {})

                if mark:
                    mark_answers = mark.answers
                    data['mark'] = {}
                    data['mark']['score'] = mark.score
                    data['mark']['rank'] = mark.rank
                    data['mark']['answers'] = mark_answers
                    data['mark']['bonus'] = mark.bonus

                for quiz in data.get('quizes', []):
                    for prod in quiz.get('products', []):
                        if quiz['id'] in paper_answers \
                            and prod['id'] in paper_answers[quiz['id']]:
                            prod['score'] = paper_answers[quiz['id']][
                                prod['id']]

                        if mark:
                            prod['is_mark'] = (quiz['id'] in mark_answers) \
                                and (prod['id'] == mark_answers[quiz['id']])

                if 'answers' in data:
                    del data['answers']

            res['meta']['earliest'] = earliest
            return self.create_response(request, res)
예제 #11
0
class UserResource(BaseResource):
    accounts = fields.ReferencedListField(
        of='apis.base.resources.AccountResource',
        attribute='accounts',
        full=True,
        null=True)

    class Meta:
        queryset = User.objects()
        allowed_methods = ('get', )
        detail_allowed_methods = ('get', 'post')
        authentication = UserAuthentication()
        authorization = Authorization()
        always_return_data = True
        fields = [
            'id', 'username', 'email', 'screen_name', 'phone', 'device',
            'accounts', 'is_active', 'last_login', 'date_joined'
        ]
        ordering = ('username', 'last_login', 'date_joined')

    def prepend_urls(self):
        return [
            url(r"^(?P<resource_name>%s)/login%s$" % (self._meta.resource_name, trailing_slash()), \
                self.wrap_view('login'), name="api_login"),
            url(r"^(?P<resource_name>%s)/open_login%s$" % (self._meta.resource_name, trailing_slash()), \
                self.wrap_view('open_login'), name="api_open_login"),
            url(r"^(?P<resource_name>%s)/bind%s$" % (self._meta.resource_name, trailing_slash()), \
                self.wrap_view('bind'), name="api_bind"),
            url(r"^(?P<resource_name>%s)/logout%s$" % (self._meta.resource_name, trailing_slash()), \
                self.wrap_view('logout'), name="api_logout"),
            url(r"^(?P<resource_name>%s)/register%s$" % (self._meta.resource_name, trailing_slash()), \
                self.wrap_view('register'), name="api_register"),
            url(r"^(?P<resource_name>%s)/(?P<user_id>\w+)/chgpwd%s$" % (self._meta.resource_name, trailing_slash()), \
                self.wrap_view('change_password'), name="api_change_password"),
            url(r"^(?P<resource_name>%s)/fgtpwd%s$" % (self._meta.resource_name, trailing_slash()), \
                self.wrap_view('forget_password'), name="api_forget_password"),
            url(r"^(?P<resource_name>%s)/(?P<user_id>\w+)/rstpwd%s$" % (self._meta.resource_name, trailing_slash()), \
                self.wrap_view('reset_password'), name="api_reset_password"),
            url(r"^(?P<resource_name>%s)/auth%s$" % (self._meta.resource_name, trailing_slash()), \
                self.wrap_view('auth'), name="api_auth"),
        ]

    def post_detail(self, request, **kwargs):
        return self.patch_detail(request, **kwargs)

    def dehydrate(self, bundle):
        for k in bundle.data:
            if k == 'phone' and bundle.data[k] is None:
                bundle.data[k] = ''
        return bundle

    def to_json(self, object_user):
        data = {
            field: getattr(object_user, field)
            for field in self._meta.fields if getattr(object_user, field)
        }
        if 'accounts' in data and len(data['accounts']):
            data['accounts'] = [{
                field: getattr(acc, field)
                for field in acc._fields
            } for acc in data['accounts']]
        return data

    def auth(self, request, **kwargs):
        """
        Just help check if the request is authenticated.
        """
        return self.create_response(request, {'response': request.user})

    def validate_password(self, password=''):
        return (len(password) >= 6 and len(password) <= 20)

    def bind(self, request, **kwargs):
        self.method_check(request, allowed=('post', ))
        u = request.user
        if not u.is_authenticated():
            return self.create_response(
                request, {'error_message': 'no login user to bind'},
                response_class=HttpUnauthorized)

        data = self.deserialize(request,
                                request.body,
                                format=request.META.get(
                                    'CONTENT_TYPE', 'application/json'))
        aid = data.get('aid')
        platform = data.get('platform')
        screen_name = data.get('screen_name')
        token = data.get('token')
        bind_type = data.get('bind_type')
        validation_error = {}

        for var in ['aid', 'platform', 'screen_name', 'bind_type']:
            if not locals().get(var):
                validation_error[var] = 'the param is required.'
                continue

        if validation_error:
            return self.create_response(request, validation_error,
                                        HttpBadRequest)

        Account.objects(aid=aid, platform=platform).update_one( \
            set__screen_name=screen_name, set__token=token, upsert=True)
        account = Account.objects(aid=aid, platform=platform).first()
        users = User.objects(accounts=account)

        for user in users:
            if user.id != u.id:
                user.accounts.remove(account)
                user.save()

        if bind_type == 'add':
            if account in u.accounts:
                return self.create_response(request, {
                    'error_code': 1,
                    'error_message': 'already binding'
                })
            u.accounts.append(account)
            u.save()

        elif bind_type == 'delete':
            if account not in u.accounts:
                return self.create_response(
                    request, {
                        'error_code': 2,
                        'error_message': 'already unbinding'
                    })
            if not u.email and len(u.accounts) == 1:
                return self.create_response(
                    request, {
                        'error_code':
                        3,
                        'error_message':
                        'open login user can not unbind the account'
                    })
            u.accounts.remove(account)
            u.save()
            account.delete()

        return self.create_response(request, self.to_json(u))

    def open_login(self, request, **kwargs):
        try:
            self.method_check(request, allowed=('post', ))
            data = self.deserialize(request,
                                    request.body,
                                    format=request.META.get(
                                        'CONTENT_TYPE', 'application/json'))
            aid = str(data.get('aid'))
            platform = data.get('platform')
            screen_name = data.get('screen_name')
            token = data.get('token')
            device_platform = data.get('device_platform')
            device_id = data.get('device_id')
            device = u'{}_{}'.format(device_platform, device_id)

            if not aid or not platform or not screen_name:
                return self.create_response(request, \
                    {'error_code': 1, 'error_message': 'aid, platform, screen_name is not correct'}, HttpBadRequest)

            # old user
            account = Account.objects(aid=aid, platform=platform).first()
            if account:
                user = User.objects(accounts=account).first()
                if not user:
                    account.delete()
                    return self.create_response(request, \
                        {'error_code': 2, 'error_message': 'error existing account with no user binded, please retry'}, HttpBadRequest)

                account.screen_name = screen_name
                account.token = token
                account.save()
                user.backend = AUTHENTICATION_BACKENDS[0]
                login(request, user)
                return self.create_response(request, self.to_json(user))

            # new user
            if User.objects(device=device):
                return self.create_response(
                    request, {'error_message': 'device has been registered'},
                    HttpForbidden)

            account = Account(
                aid=aid,
                platform=platform,
                screen_name=screen_name,
                token=token,
            )
            account.save()
            new_user = User().create_user(
                username=str(ObjectId()),
                password=SECRET_KEY,
                screen_name=screen_name,
                device=device,
                accounts=[account],
            )

            user = authenticate(username=new_user.username,
                                password=SECRET_KEY)
            login(request, user)
            return self.create_response(request, self.to_json(user))
        except:
            traceback.print_exc()

    def login(self, request, **kwargs):
        self.method_check(request, allowed=('post', ))
        data = self.deserialize(request,
                                request.body,
                                format=request.META.get(
                                    'CONTENT_TYPE', 'application/json'))
        username = data.get('username')
        password = data.get('password')
        user = authenticate(username=username, password=password)
        if user:
            login(request, user)
            return self.create_response(request, self.to_json(user))
        else:
            return self.create_response(
                request, {'error_message': 'incorrect username or password'},
                HttpUnauthorized)

    def logout(self, request, **kwargs):
        if request.user and request.user.is_authenticated():
            Notification.objects(user=request.user).delete()
            logout(request)
            return self.create_response(request, {'success': True})
        else:
            return self.create_response(request,
                                        {'error_message': 'no user to logout'},
                                        HttpUnauthorized)

    def register(self, request, **kwargs):
        self.method_check(request, allowed=('post', ))
        data = self.deserialize(request,
                                request.body,
                                format=request.META.get(
                                    'CONTENT_TYPE', 'application/json'))
        password = data.get('password')
        screen_name = data.get('screen_name')
        email = data.get('email')
        username = email
        phone = data.get('phone')
        device_platform = data.get('device_platform')
        device_id = data.get('device_id')
        device = u'{}_{}'.format(device_platform, device_id)
        validation_error = {}

        for var in [
                'password', 'device_id', 'device_platform', 'email',
                'screen_name'
        ]:
            if not locals().get(var):
                validation_error[var] = u'the post param is required'
                continue

        if validation_error:
            return self.create_response(request, validation_error,
                                        HttpBadRequest)

        user = User.objects(
            Q(username=username) | Q(device=device) | Q(email=email)
            | Q(screen_name=screen_name)).first()
        if user:
            if user.username == username:
                return self.create_response(request, {
                    'error_code': 1,
                    'error_message': 'user exists'
                })
            if user.email == email:
                return self.create_response(request, {
                    'error_code': 2,
                    'error_message': 'email exists'
                })
            if user.device == device:
                return self.create_response(
                    request, {
                        'error_code':
                        3,
                        'error_message':
                        u'device has been registered {}'.format(device)
                    })
            if user.screen_name == screen_name:
                return self.create_response(
                    request, {
                        'error_code': 4,
                        'error_message': 'screen_name exists'
                    })

        if not self.validate_password(password):
            return self.create_response(request, {
                'error_code': 5,
                'error_message': 'password invalid'
            })

        try:
            new_user = User().create_user(
                username=username,
                password=password,
                email=email,
                screen_name=screen_name,
                phone=phone,
                device=device,
            )
        except ValidationError:
            return self.create_response(
                request, {
                    'error_code': 6,
                    'error_message': 'email format not correct'
                })

        user = authenticate(username=username, password=password)
        login(request, user)
        return self.create_response(request, self.to_json(user))

    def change_password(self, request, **kwargs):
        self.method_check(request, allowed=('post', ))
        user_id = kwargs.get('user_id')
        if not request.user.is_authenticated() or request.user.id != user_id:
            return self.create_response(request, {
                'error_code': 1,
                'error_message': 'user error'
            }, HttpUnauthorized)

        data = self.deserialize(request,
                                request.body,
                                format=request.META.get(
                                    'CONTENT_TYPE', 'application/json'))
        old_password = data.get('old_password')
        new_password = data.get('new_password')
        confirm_password = data.get('confirm_password')

        if old_password == new_password:
            return self.create_response(request, \
                {'error_code': 1, 'error_message': 'old password must be different from new password'}, HttpBadRequest)
        if new_password != confirm_password:
            return self.create_response(request, \
                {'error_code': 2, 'error_message': 'new password must be equal with confirm password'}, HttpBadRequest)
        if not self.validate_password(new_password):
            return self.create_response(request, \
                {'error_code': 3, 'error_message': 'new password invalid, should be 6-20 digits'}, HttpBadRequest)

        u = User.objects(id=user_id).first()
        user = authenticate(username=u.username, password=old_password)
        if not user or not user.is_authenticated:
            return self.create_response(request, {
                'error_code': 1,
                'error_message': 'old password error'
            })

        u.set_password(new_password)
        u.save()
        return self.create_response(request, {'success': True})

    def forget_password(self, request, **kwargs):
        try:
            self.method_check(request, allowed=('post', ))
            data = self.deserialize(request,
                                    request.body,
                                    format=request.META.get(
                                        'CONTENT_TYPE', 'application/json'))
            user = User.objects(email=data.get('email')).first()
            if user is None:
                return self.create_response(request,
                                            {'error_message': 'email error'},
                                            HttpBadRequest)

            token = signing.dumps(user.id, key=SECRET_KEY)
            PwdRstToken.objects(user=user).update_one(
                set__token=token,
                set__generated_at=datetime.utcnow(),
                set__expires=10,
                set__validated=False,
                upsert=True)

            if DEBUG:
                link = reverse('api_reset_password',
                               kwargs={
                                   'resource_name': self._meta.resource_name,
                                   'api_name': 'v1',
                                   'user_id': user.id
                               })
            else:
                link = u'http://{}/{}/api/v1/user/{}/rstpwd/'.format(
                    HOST, APP_NAME, user.id)
            url = u'{}?token={}&format=json'.format(
                request.build_absolute_uri(link), token)
            c = Context({'user': user, 'APP_NAME': APP_NAME, 'url': url})
            html_content = loader.get_template('fgtpwd.html').render(c)
            email = EmailMultiAlternatives(u'验证登录邮箱【{}安全中心 】'.format(APP_NAME),
                                           '', EMAIL_HOST_USER, [user.email])
            email.attach_alternative(html_content, "text/html")
            email.send()
            return self.create_response(request, {'success': True})
        except:
            traceback.print_exc()
            raise

    def reset_password(self, request, **kwargs):
        user_id = kwargs.get('user_id')
        token = request.GET.get('token')
        user = User.objects.get(id=user_id)
        prt = PwdRstToken.objects(
            user=user, token=token).order_by('-generated_at').first()

        if request.method == 'GET':
            if prt is None:
                return HttpResponse(u'此链接不存在,用户不合法')
            elif (prt.generated_at +
                  timedelta(minutes=prt.expires)) < datetime.utcnow():
                return HttpResponse(u'链接已过期')

            return render(request, 'rstpwd.html', {
                'username': user.username,
                'user_id': user.id,
                'token': token,
            })

        elif request.method == 'POST':
            password = request.POST.get('password')
            confirm_password = request.POST.get('confirm_password')
            invalid_message = ''

            if prt is None or \
                (prt.generated_at + timedelta(minutes=prt.expires)) < datetime.utcnow():
                invalid_message = u'此密码修改已经失效,请重新申请忘记密码'

            if prt.validated:
                invalid_message = u'已修改过密码'

            elif not password or not confirm_password:
                invalid_message = u'密码不得为空'

            elif password != confirm_password:
                invalid_message = u'新密码与确认密码不一致'

            elif not self.validate_password(password):
                invalid_message = u'密码应该在6-20 位'

            if invalid_message:
                return render(
                    request, 'rstpwd.html', {
                        'invalid_message': invalid_message,
                        'username': user.username,
                        'user_id': user.id,
                        'token': token,
                    })

            else:
                user.set_password(password)
                prt.validated = True
                user.save()
                prt.save()
                return HttpResponse('修改成功')
예제 #12
0
class VosaeUserResource(WakeUpMixinResource, ZombieMixinResource,
                        TenantResource):
    full_name = base_fields.CharField(
        attribute='get_full_name',
        readonly=True,
        help_text=HELP_TEXT['vosae_user']['full_name'])
    email = base_fields.CharField(attribute='email',
                                  help_text=HELP_TEXT['vosae_user']['email'])
    status = base_fields.CharField(attribute='status',
                                   blank=True,
                                   help_text=HELP_TEXT['vosae_user']['status'])
    photo_uri = base_fields.CharField(
        attribute='photo_uri',
        readonly=True,
        null=True,
        blank=True,
        help_text=HELP_TEXT['vosae_user']['photo_uri'])
    specific_permissions = base_fields.DictField(
        attribute='specific_permissions',
        blank=True,
        help_text=HELP_TEXT['vosae_user']['specific_permissions'])
    permissions = base_fields.ListField(
        readonly=True, help_text=HELP_TEXT['vosae_user']['permissions'])

    groups = fields.ReferencedListField(
        of='core.api.resources.VosaeGroupResource',
        attribute='groups',
        null=True,
        blank=True,
        help_text=HELP_TEXT['vosae_user']['groups'])
    settings = fields.EmbeddedDocumentField(
        embedded='core.api.resources.VosaeUserSettingsResource',
        attribute='settings',
        help_text=HELP_TEXT['vosae_user']['settings'])

    class Meta(TenantResource.Meta):
        resource_name = 'user'
        queryset = VosaeUser.objects.all()
        list_allowed_methods = ('get', 'post')
        excludes = ('tenant', )
        filtering = {"email": ('exact', )}

    @classmethod
    def post_create(self, sender, resource, bundle, **kwargs):
        """
        Post create hook.

        Fills initial data (based on request's language) after VosaeUser creation
        """
        # Fill user initial data (Tenant and VosaeUser are required)
        fill_user_initial_data.delay(bundle.obj, bundle.request.LANGUAGE_CODE)

    def hydrate_email(self, bundle):
        """
        Email can only be used on POST (creation) in order to link the
        :class:`~core.models.VosaeUser` to the Django user.
        """
        if bundle.request.method.lower() != 'post':
            bundle.data.update(email=bundle.obj.email)
        return bundle

    def dehydrate_permissions(self, bundle):
        """Returns the list of acquired permissions"""
        return list(bundle.obj.permissions.acquired)