def create(self, validated_data): tenant = self.context.get('request').user.tenant contact_count = Contact.objects.filter(is_deleted=False).count() if tenant.billing.is_free_plan and contact_count >= settings.FREE_PLAN_ACCOUNT_CONTACT_LIMIT: raise serializers.ValidationError({ 'limit_reached': _('You\'ve reached the limit of contacts for the free plan.'), }) instance = super(ContactSerializer, self).create(validated_data) credentials = get_credentials('moneybird') if has_required_tier(2) and credentials and credentials.integration_context.get('auto_sync'): self.send_moneybird_contact(validated_data, instance, credentials) # Track newly ceated accounts in segment. if not settings.TESTING: analytics.track( self.context.get('request').user.id, 'contact-created', { 'creation_type': 'automatic' if is_external_referer(self.context.get('request')) else 'manual', }, ) return instance
def validate(self, attrs): password = attrs.get('password') password_confirmation = attrs.get('password_confirmation') email = attrs.get('email') webhooks = attrs.get('webhooks') if webhooks and not has_required_tier(2): raise PermissionDenied if self.instance: # If there's an instance, it means we're updating. if password and not password_confirmation: raise serializers.ValidationError({ 'password_confirmation': _('When changing passwords, you need to confirm with your current password.' ), }) if email and email != self.instance.email and not password_confirmation: raise serializers.ValidationError({ 'password_confirmation': _('When changing email adresses, you need to confirm with your current password.' ), }) return super(LilyUserSerializer, self).validate(attrs)
def create(self, validated_data): tenant = self.context.get('request').user.tenant contact_count = Contact.objects.filter(is_deleted=False).count() if tenant.billing.is_free_plan and contact_count >= settings.FREE_PLAN_ACCOUNT_CONTACT_LIMIT: raise serializers.ValidationError({ 'limit_reached': _('You\'ve reached the limit of contacts for the free plan.'), }) instance = super(ContactSerializer, self).create(validated_data) credentials = get_credentials('moneybird') if has_required_tier( 2) and credentials and credentials.integration_context.get( 'auto_sync'): self.send_moneybird_contact(validated_data, instance, credentials) # Track newly ceated accounts in segment. if not settings.TESTING: analytics.track( self.context.get('request').user.id, 'contact-created', { 'creation_type': 'automatic' if is_external_referer( self.context.get('request')) else 'manual', }, ) return instance
def get_context_data(self, **kwargs): account_admin = self.request.user.tenant.admin.full_name kwargs = super(BaseView, self).get_context_data(**kwargs) kwargs.update({ 'INTERCOM_APP_ID': settings.INTERCOM_APP_ID, 'SENTRY_FRONTEND_PUBLIC_DSN': settings.SENTRY_FRONTEND_PUBLIC_DSN, 'BILLING_ENABLED': settings.BILLING_ENABLED, 'SLACK_LILY_CLIENT_ID': settings.SLACK_LILY_CLIENT_ID, 'DEBUG': settings.DEBUG, 'account_admin': account_admin, }) if not has_required_tier(1): account_count = Account.objects.filter(is_deleted=False).count() contact_count = Contact.objects.filter(is_deleted=False).count() email_account_count = EmailAccount.objects.filter( is_deleted=False).count() kwargs.update({ 'limit_reached': { 'accounts': account_count >= settings.FREE_PLAN_ACCOUNT_CONTACT_LIMIT, 'contacts': contact_count >= settings.FREE_PLAN_ACCOUNT_CONTACT_LIMIT, 'email_accounts': email_account_count >= settings.FREE_PLAN_EMAIL_ACCOUNT_LIMIT, }, }) return kwargs
def authenticate(self, request): for authenticator_cls in self.authenticators: authenticator = authenticator_cls() auth_tuple = authenticator.authenticate(request) if auth_tuple: if isinstance(authenticator, TokenAuthentication) or isinstance( authenticator, TokenGETAuthentication): if not has_required_tier(2, tenant=auth_tuple[0].tenant): # Tenant is on free plan, so no external API access. raise PermissionDenied({ 'detail': ('API access has been disabled because you are on the free plan.' 'Please upgrade to continue using the API') }) break else: # All authentication failed. return None # Set the current user for the tenant filters. set_current_user(auth_tuple[0]) return auth_tuple
def update(self, instance, validated_data): if not self.context.get('request').user.is_admin: raise PermissionDenied if not has_required_tier(1): # Settings only allowed for 'Team' plan and higher. team_features = ['timelogging_enabled', 'billing_default'] # Tenant doesn't have the required tier, so check if their API request # contains any of the blocked settings. if any(x in validated_data for x in team_features): raise PermissionDenied return super(TenantSerializer, self).update(instance, validated_data)
def create(self, validated_data): tenant = self.context.get('request').user.tenant contact_count = Contact.objects.filter(is_deleted=False).count() if tenant.billing.is_free_plan and contact_count >= settings.FREE_PLAN_ACCOUNT_CONTACT_LIMIT: raise serializers.ValidationError({ 'limit_reached': _('You\'ve reached the limit of contacts for the free plan.'), }) instance = super(ContactSerializer, self).create(validated_data) credentials = get_credentials('moneybird') if has_required_tier( 2) and credentials and credentials.integration_context.get( 'auto_sync'): self.send_moneybird_contact(validated_data, instance, credentials) return instance
def update(self, instance, validated_data): # Save the current data for later use. original_data = { 'full_name': instance.full_name, } email_addresses = instance.email_addresses.all() if len(email_addresses) == 1: original_data.update({ 'original_email_address': email_addresses[0].email_address }) instance = super(ContactSerializer, self).update(instance, validated_data) credentials = get_credentials('moneybird') if has_required_tier(2) and credentials and credentials.integration_context.get('auto_sync'): self.send_moneybird_contact(validated_data, instance, credentials, original_data) return instance
def token(self, request, *args, **kwargs): """ This view only returns the token of the currently logged in user GET returns the current token POST generates a new token DELETE removes the current token """ if not has_required_tier(2): return Response(status=status.HTTP_403_FORBIDDEN) if request.method in ('DELETE', 'POST'): Token.objects.filter(user=request.user).delete() if request.method == 'DELETE': return Response(status=status.HTTP_204_NO_CONTENT) else: Token.objects.create(user=request.user) serializer = LilyUserTokenSerializer(request.user) return Response(serializer.data)
def validate(self, data): password = data.get('password') password_confirmation = data.get('password_confirmation') email = data.get('email') webhooks = data.get('webhooks', []) if webhooks and not has_required_tier(2): raise PermissionDenied for webhook in webhooks: if any(allowed_host in webhook['url'] for allowed_host in settings.ALLOWED_HOSTS): raise serializers.ValidationError({ 'url': _('You should set your url to something external to Lily.') }) # If there's an instance, it means we're updating. if self.instance: # Only validate the current password if the user has a usable_password. # Users with social auth don't have one, but they can set one. if self.instance.has_usable_password(): if password and not password_confirmation: raise serializers.ValidationError({ 'password_confirmation': _('When changing passwords, you need to confirm with your current password.' ), }) if email and email != self.instance.email and not password_confirmation: raise serializers.ValidationError({ 'password_confirmation': _('When changing email adresses, you need to confirm with your current password.' ), }) return super(LilyUserSerializer, self).validate(data)
def validate(self, data): password = data.get('password') password_confirmation = data.get('password_confirmation') email = data.get('email') webhooks = data.get('webhooks', []) if webhooks and not has_required_tier(2): raise PermissionDenied for webhook in webhooks: if any(allowed_host in webhook['url'] for allowed_host in settings.ALLOWED_HOSTS): raise serializers.ValidationError({ 'url': _( 'You should set your url to something external to Lily.' ) }) # If there's an instance, it means we're updating. if self.instance: # Only validate the current password if the user has a usable_password. # Users with social auth don't have one, but they can set one. if self.instance.has_usable_password(): if password and not password_confirmation: raise serializers.ValidationError({ 'password_confirmation': _( 'When changing passwords, you need to confirm with your current password.' ), }) if email and email != self.instance.email and not password_confirmation: raise serializers.ValidationError({ 'password_confirmation': _( 'When changing email adresses, you need to confirm with your current password.' ), }) return super(LilyUserSerializer, self).validate(data)
def authenticate(self, request): for authenticator_cls in self.authenticators: authenticator = authenticator_cls() auth_tuple = authenticator.authenticate(request) if auth_tuple: if isinstance(authenticator, TokenAuthentication) or isinstance(authenticator, TokenGETAuthentication): if not has_required_tier(2, tenant=auth_tuple[0].tenant): # Tenant is on free plan, so no external API access. raise PermissionDenied({ 'detail': ( 'API access has been disabled because you are on the free plan.' 'Please upgrade to continue using the API' ) }) break else: # All authentication failed. return None # Set the current user for the tenant filters. set_current_user(auth_tuple[0]) return auth_tuple
def update(self, instance, validated_data): # Save the current data for later use. original_data = { 'full_name': instance.full_name, } email_addresses = instance.email_addresses.all() if len(email_addresses) == 1: original_data.update( {'original_email_address': email_addresses[0].email_address}) instance = super(ContactSerializer, self).update(instance, validated_data) credentials = get_credentials('moneybird') if has_required_tier( 2) and credentials and credentials.integration_context.get( 'auto_sync'): self.send_moneybird_contact(validated_data, instance, credentials, original_data) return instance
def has_permission(self, request, view): # We'll just put the default tier at two since that's the most common requirement. required_tier = getattr(view, 'required_tier', 2) # API access isn't available for the free and cheapest paid plan. return has_required_tier(required_tier)