示例#1
0
    def change_password(self, request):
        """
		Change the password from an old password

		Request:

		POST user/change_password/
		{
			"old_password": str,
			"new_password": str
		}

		Response:
		Same as GET user/{id}/

		"""
        if request.method != 'PUT':
            raise BinderMethodNotAllowed()

        self._require_model_perm('change_own_password', request)

        decoded = request.body.decode()
        try:
            body = json.loads(decoded)
        except ValueError:
            raise BinderRequestError(
                _('Invalid request body: not a JSON document.'))

        user = request.user

        errors = {}
        for item in ['old_password', 'new_password']:
            if body.get(item) is None:
                errors[item] = ['missing']

        if not user.check_password(body.get('old_password')):
            errors['old_password'] = ['incorrect']

        if len(errors) != 0:
            raise BinderValidationError(errors)

        password = body.get('new_password')
        try:
            password_validation.validate_password(password, user)
        except ValidationError as ve:
            validation_errors = {'new_password': ve.messages}
            raise BinderValidationError(validation_errors)

        user.set_password(password)
        user.save()
        logger.info('password changed for {}/{}'.format(user.id, user))

        if user == request.user:
            """
			No need to change the password of an user that is not our own
			"""
            update_session_auth_hash(request, user)

        return self.respond_with_user(request, user.id)
示例#2
0
 def _binder_unset_relation_caretaker(self, request):
     raise BinderValidationError({
         'animal': {
             self.pk: {
                 'caretaker': [{
                     'code': 'cant_unset',
                     'message': 'You can\'t unset zoo.',
                 }]
             }
         }
     })
示例#3
0
    def activate(self, request, pk=None):
        """
		Adds an endpoint to activate an user. Also logs in the user

		Request:

		PUT user/{id}/activate/
		{
			"activation_code": string
		}

		Response:

		Same as GET user/{id}/
		"""
        if request.method != 'PUT':
            raise BinderMethodNotAllowed()

        self._require_model_perm('activate', request)

        decoded = request.body.decode()
        try:
            body = json.loads(decoded)
        except ValueError:
            raise BinderRequestError(
                _('Invalid request body: not a JSON document.'))

        errors = {}
        for item in ['activation_code']:
            if body.get(item) is None:
                errors[item] = ['missing']
        if len(errors) != 0:
            raise BinderValidationError(errors)

        try:
            user = self.model._default_manager.get(pk=pk)
        except (TypeError, ValueError, OverflowError, self.model.DoesNotExist):
            user = None
        if user is None or not self.token_generator.check_token(
                user, body.get('activation_code')):
            raise BinderNotFound()

        logger.info('login for {}/{} via successful activation'.format(
            user.id, user))

        user.is_active = True
        user.save()
        self.auth_login(request, user)
        return self.respond_with_user(request, user.id)
示例#4
0
    def chart(self, request):
        tx_qs = TransactionView().get_queryset(request=request)

        start_date = request.GET.get('start_date', None)
        end_date = request.GET.get('end_date', None)

        if not start_date or not end_date:
            raise BinderValidationError('start_date and end_date are required')

        txs = tx_qs.filter(date__gte=start_date,
                           date__lte=end_date).order_by('date')

        # Find the initial balance
        starting_balance = Balance.get_at_date(start_date, request.user)
        working_balance = 0
        if starting_balance is not None:
            working_balance = starting_balance

        start_date = datetime.strptime(start_date, '%Y-%m-%d')
        end_date = datetime.strptime(end_date, '%Y-%m-%d')

        date_pointer = start_date
        days_per_bin = 1
        bins = []

        while date_pointer < end_date:
            bins.append(
                (date_pointer.strftime('%Y-%m-%d'),
                 working_balance))  # A chart bin is a (date, balance) tuple

            # increment the working balance for every transaction in that bin
            next_date = date_pointer + timedelta(days_per_bin)
            upper_bound = min(end_date,
                              next_date)  # Don't overstep the end_date bound

            balance_change = 0
            txs = tx_qs.filter(date__gte=date_pointer,
                               date__lt=upper_bound).order_by('date')
            if len(txs):
                balance_change = txs.aggregate(result=Sum('amount'))['result']

            working_balance += balance_change
            date_pointer = next_date

        # Add the final bin, this probably isn't necessary if the iteration is better
        bins.append((date_pointer.strftime('%Y-%m-%d'), working_balance))

        return JsonResponse({'data': bins})
示例#5
0
    def rotate(self, request):
        body = jsonloads(request.body)

        form = RotateForm(body)

        if not form.is_valid():
            raise BinderValidationError(form.errors)

        angle = body['angle']

        for s in self._get_images(body, request):
            file = self._get_file(s)
            src_im = Image.open(file)
            rotated_img = src_im.rotate(angle, expand=1)
            rotated_img.save(file.file.name, overwrite=True)
            file.close()
        return JsonResponse([])
示例#6
0
    def scrape(self, request):
        # With this new import, the pending transaction should be removed
        Transaction.objects.filter(type="PENDING").delete()

        last_import = DataImport.objects.order_by(
            '-last_transaction_date').first()

        if last_import:
            start_date = last_import.last_transaction_date
        else:
            start_date = datetime.date.today() - datetime.timedelta(90)

        end_date = datetime.date.today()

        params = {
            "startDate": start_date.strftime('%Y-%m-%d'),
            "endDate": end_date.strftime('%Y-%m-%d')
        }

        r = requests.post(os.environ.get('SCRAPER_URL'), json=params)

        if r.status_code == 400:
            raise BinderValidationError(
                'Error encountered during scraping: {}'.format(r.text))

        parsed_balance = int(r.headers["X-Account-Budget"].replace('.', ''))

        i = DataImport(file_path="", user=request.user)
        i.save()

        import_range = self.get_import_range(request.user)

        csv_contents = r.text.replace('\r', '')

        i.parse(r.text.split('\n'), import_range, request.user)
        i.calculate_metrics()

        # Rerun the queries on the newly imported data
        # so the new transactions get the correct category labels
        Query.run_all(request.user)

        # Set balance to the new balance
        b = Balance(user=request.user, after_import=i, amount=parsed_balance)
        b.save()

        return self.get(request, pk=i.id)
示例#7
0
    def _get_images(self, body, request):
        '''
		Get all the scans defined in the body's ids paramater, or retruns a validation error if one of the objects
		does not exist
		'''
        ids = body['ids']

        scans = []
        for i in ids:
            try:
                scans.append(self.model.objects.get(pk=i))
            except ObjectDoesNotExist:
                raise BinderValidationError(
                    {'ids': ['ImageObject with id {} not found'.format(i)]})

        if isinstance(self, PermissionView):
            self.scope_change_list(request, scans, {})
        return scans
示例#8
0
    def crop(self, request):
        body = jsonloads(request.body)

        form = CropForm(body)
        if not form.is_valid():
            raise BinderValidationError(form.errors)

        x_1 = body['x_1']
        x_2 = body['x_2']
        y_1 = body['y_1']
        y_2 = body['y_2']

        for s in self._get_images(body, request):
            file = self._get_file(s)
            src_im = Image.open(file)
            rotated_img = src_im.crop((x_1, y_1, x_2, y_2))
            rotated_img.save(file.file.name, overwrite=True)
            file.close()

        return JsonResponse([])
示例#9
0
    def _reset_pass_for_user(self, request, user_id, token, password):
        """
		Helper function that actually resets the password for an user
		"""
        try:
            user = self.model._default_manager.get(pk=user_id)
        except (TypeError, ValueError, OverflowError, self.model.DoesNotExist):
            user = None

        if user is None or not self.token_generator.check_token(user, token):
            raise BinderNotFound()

        logger.info('login for {}/{} via successful password reset'.format(
            user.id, user))

        try:
            password_validation.validate_password(password, user)
        except ValidationError as ve:
            raise BinderValidationError({'password': ve.messages})

        user.set_password(password)
        user.save()
        self.auth_login(request, user)
        return self.respond_with_user(request, user.id)
示例#10
0
    def reset_password(self, request, pk=None):
        """
		Resets the password from an reset code

		Request:

		POST user/reset_password/
		{
			"reset_code": str,
			"password": str
		}

		Response:

		Same as GET user/{id}/

		"""

        self._require_model_perm('reset_password', request)

        decoded = request.body.decode()
        try:
            body = json.loads(decoded)
        except ValueError:
            raise BinderRequestError(
                _('Invalid request body: not a JSON document.'))

        errors = {
            item: 'missing'
            for item in ['reset_code', 'password'] if item not in body
        }
        if errors:
            raise BinderValidationError(errors)

        return self._reset_pass_for_user(request, int(pk), body['reset_code'],
                                         body['password'])
示例#11
0
文件: budget.py 项目: stam/finance
    def chart(self, request):
        tx_qs = TransactionView().get_queryset(request=request)

        c_saving = Category.objects.filter(name='Saving',
                                           user=request.user).first()
        c_work = Category.objects.filter(name='Work',
                                         user=request.user).first()

        print(c_work.id)

        BUCKET_INCOME = 'Income'
        BUCKET_SAVING = 'Saving'
        BUCKET_SPENT = 'Total_spent',

        # find income from last month
        # find saving from this month

        budgets = Budget.objects.filter(user=request.user).all()
        cat_to_budget_mapping = {}
        spent_per_category = {}
        output = {
            None: {
                'name': 'Uncategorised',
                'total': 0,
                'current': 0,
                'count': 0
            },
            BUCKET_SAVING: {
                'name': 'Saving',
                'total': -1,
                'current': 0,
                'count': 0
            },
            BUCKET_INCOME: {
                'name': 'Income',
                'total': -1,
                'current': 0,
                'count': 0
            },
            BUCKET_SPENT: {
                'name': 'Total spent',
                'total': -1,
                'current': 0,
                'count': 0
            },
        }
        for budget in budgets:
            output[budget.id] = {
                'name': budget.name,
                'total': budget.amount,
                'categories': {},
                'current': 0,
                'count': 0
            }
            for cat in budget.categories.all():
                cat_to_budget_mapping[cat.id] = budget
                output[budget.id]['categories'][cat.id] = {
                    'id': cat.id,
                    'name': cat.name,
                    'color': cat.color,
                    'icon': cat.icon,
                    'total': 1000,
                    'current': 0,
                    'count': 0
                }

        start_date = request.GET.get('start_date', None)
        end_date = request.GET.get('end_date', None)

        if not start_date or not end_date:
            raise BinderValidationError('start_date and end_date are required')

        txs = tx_qs.filter(date__gte=start_date,
                           date__lte=end_date).order_by('date').all()

        spent_per_category = {}

        for transaction in txs:
            cat_id = transaction.category_id

            budget_id = None
            if cat_id is not None:
                if cat_id not in spent_per_category:
                    spent_per_category[cat_id] = {
                        'name': budget.name,
                        'total': budget.amount,
                        'current': 0,
                        'count': 0
                    }
                if cat_id == c_saving.id:
                    budget_id = BUCKET_SAVING
                elif cat_id == c_work.id:
                    budget_id = BUCKET_INCOME
                else:
                    budget = cat_to_budget_mapping.get(cat_id)

                    output[BUCKET_SPENT]['current'] -= transaction.amount
                    output[BUCKET_SPENT]['count'] += 1

                    if budget:
                        budget_id = budget.id

            # The saving/income/spent buckets don't need this
            if 'categories' in output[budget_id]:
                output[budget_id]['categories'][cat_id][
                    'current'] -= transaction.amount
                output[budget_id]['categories'][cat_id]['count'] += 1
            output[budget_id]['current'] -= transaction.amount
            output[budget_id]['count'] += 1

        return JsonResponse({
            'data': list(output.values()),
            'meta': {
                'total_records': len(budgets)
            }
        })
示例#12
0
    def send_activation_email(self, request):
        """
		Endpoint that can be used to send an activation mail for an user.
		Calls the _send_activation_email callback if the user is succesfully activated

		Request:

		POST
		{
			"email": "email"
		}

		Response:
		{
			"code": code
		}

		Possible codes:

		sent			Mail is send sucessfully
		already active 	User is already active, no mail was send
		blacklisted		User was not activated

		"""
        if request.method != 'PUT':
            raise BinderMethodNotAllowed()

        # For lack of a better check
        self._require_model_perm('reset_password', request)

        decoded = request.body.decode()
        try:
            body = json.loads(decoded)
        except ValueError:
            raise BinderRequestError(
                _('Invalid request body: not a JSON document.'))

        logger.info('activation email attempt for {}'.format(
            body.get('email', '')))

        if body.get('email') is None:
            raise BinderValidationError({'email': ['missing']})

        try:
            user = self.model._default_manager.get(email=body.get('email'))
        except self.model.DoesNotExist:
            raise BinderNotFound()

        if user.is_active:
            if user.last_login is None:
                # TODO: Figure out a way to make this customisable without
                # allowing injection of arbitrary URLs (phishing!)
                self._send_activation_email(request, user)
                response = JsonResponse({'code': 'sent'})
                response.status_code = 201
            else:
                response = JsonResponse({'code': 'already active'})
        else:
            response = JsonResponse({'code': 'blacklisted'})
            response.status_code = 400

        return response