Skip to content

Commit

Permalink
feat(api): Add base logic for API
Browse files Browse the repository at this point in the history
  • Loading branch information
scruwys committed Apr 2, 2022
1 parent 9352e84 commit 14f91ee
Show file tree
Hide file tree
Showing 19 changed files with 680 additions and 68 deletions.
5 changes: 3 additions & 2 deletions app/api/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 3.0.10 on 2022-04-01 11:54
# Generated by Django 3.0.10 on 2022-04-01 21:16

from django.db import migrations, models
import django.db.models.deletion
Expand All @@ -10,8 +10,8 @@ class Migration(migrations.Migration):
initial = True

dependencies = [
('authorization', '0001_initial'),
('authentication', '0001_initial'),
('authorization', '0001_initial'),
]

operations = [
Expand All @@ -24,6 +24,7 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=60)),
('is_enabled', models.BooleanField(default=True)),
('token', utils.encrypt.fields.EncryptedCharField(max_length=32)),
('last_used_at', models.DateTimeField(default=None, null=True)),
('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='api_tokens', to='authentication.Workspace')),
],
options={
Expand Down
1 change: 0 additions & 1 deletion app/api/mixins.py

This file was deleted.

15 changes: 14 additions & 1 deletion app/api/models.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
# -*- coding: utf-8 -*-
from django.db import models
from base64 import b64encode
from datetime import timedelta

from django.db import models
from django.utils import timezone

from app.authentication.models import Workspace

from utils.encrypt.fields import EncryptedCharField
from utils.mixins.models import StringPrimaryKeyModel, TimestampedModel

Expand All @@ -22,9 +26,18 @@ class ApiToken(StringPrimaryKeyModel, TimestampedModel):

token = EncryptedCharField(max_length=32, null=False, blank=False)

last_used_at = models.DateTimeField(default=None, null=True)

class Meta:
db_table = 'api_token'
unique_together = ('workspace', 'name',)

def get_secret(self):
return b64encode(':'.join([self.id, self.token]).encode('utf-8')).decode()

def touch(self):
now = timezone.now()
if self.last_used_at and (now - self.last_used_at) <= timedelta(seconds=15):
return
self.last_used_at = now
self.save()
58 changes: 0 additions & 58 deletions app/api/permissions.py

This file was deleted.

Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,20 @@

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def example_view(request, format=None):
def get_properties(request, format=None):
"""GET /api/v1/properties
"""
content = {
'status': 'request was permitted'
}
return Response(content)


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def get_property(request, format=None):
"""GET /api/v1/properties/:id
"""
content = {
'status': 'request was permitted'
}
Expand Down
Empty file.
82 changes: 82 additions & 0 deletions app/api/v1/definitions/columns.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
from rest_framework import serializers

from app.api.v1.exceptions import NotFound
from app.api.v1.serializers import ApiSerializer
from app.api.v1.views import DetailAPIView, FindAPIView, ListAPIView
from app.definitions.models import Column


class ColumnSerializer(ApiSerializer):
id = serializers.SerializerMethodField()

tags = serializers.ListField(
child=serializers.CharField(max_length=30),
max_length=10,
allow_empty=True,
allow_null=True,
required=False,
)

class Meta:
model = Column
fields = [
'id',
'name',
'tags',
'created_at',
'updated_at',
]
writable_fields = ['tags']

def get_id(self, obj):
return obj.object_id

def validate_tags(self, tags):
return list(set(tags)) if isinstance(tags, (list,)) else []

def update(self, instance, validated_data):
instance.tags = validated_data.get('tags', instance.tags)
instance.save()
return instance


class ColumnList(ListAPIView):
serializer_class = ColumnSerializer

def get_queryset(self):
filter_kwargs = {
'table_id': self.kwargs['table_id'],
'workspace': self.request.workspace,
}
return Column.objects.filter(**filter_kwargs)


class ColumnDetail(DetailAPIView):
serializer_class = ColumnSerializer

def get_object(self, pk):
get_kwargs = {
'workspace': self.request.workspace,
'object_id': pk,
}
try:
return Column.objects.get(**get_kwargs)
except Column.DoesNotExist:
raise NotFound()


class ColumnFind(FindAPIView):
serializer_class = ColumnSerializer

required_query_params = ['schema', 'table', 'name']

def find_object(self, datastore_id, query_params):
filter_kwargs = {
'workspace': self.request.workspace,
'table__schema__datastore_id': datastore_id,
'table__schema__name': query_params['schema'],
'table__name': query_params['table'],
'name': query_params['name'],
}
return Column.objects.filter(**filter_kwargs).first()
71 changes: 71 additions & 0 deletions app/api/v1/definitions/datastores.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# # -*- coding: utf-8 -*-
# from rest_framework.decorators import api_view, permission_classes
# from rest_framework.response import Response

# from app.api.permissions import IsAuthenticated


# @api_view(['GET'])
# @permission_classes([IsAuthenticated])
# def get_datastores(request, format=None):
# """GET /api/v1/datastores
# """
# content = {
# 'status': 'request was permitted'
# }
# return Response(content)


# @api_view(['GET'])
# @permission_classes([IsAuthenticated])
# def get_datastore(request, format=None):
# """GET /api/v1/datastores/:datastoreId
# """
# content = {
# 'status': 'request was permitted'
# }
# return Response(content)


# @api_view(['GET'])
# @permission_classes([IsAuthenticated])
# def get_datastore_tables(request, format=None):
# """GET /api/v1/datastores/:datastoreId/tables
# """
# content = {
# 'status': 'request was permitted'
# }
# return Response(content)


# @api_view(['PATCH'])
# @permission_classes([IsAuthenticated])
# def update_datastore(request, format=None):
# """PATCH /api/v1/datastores/:datastoreId
# """
# content = {
# 'status': 'request was permitted'
# }
# return Response(content)


# @api_view(['PATCH'])
# @permission_classes([IsAuthenticated])
# def update_datastore_properties(request, format=None):
# """PATCH /api/v1/datastores/:datastoreId/properties
# """
# content = {
# 'status': 'request was permitted'
# }
# return Response(content)


# @api_view(['PATCH'])
# @permission_classes([IsAuthenticated])
# def update_datastore_owners(request, format=None):
# """PATCH /api/v1/datastores/:datastoreId/owners
# """
# content = {
# 'status': 'request was permitted'
# }
# return Response(content)
80 changes: 80 additions & 0 deletions app/api/v1/definitions/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# -*- coding: utf-8 -*-
from rest_framework import serializers

from app.api.v1.exceptions import NotFound
from app.api.v1.serializers import ApiSerializer
from app.api.v1.views import DetailAPIView, FindAPIView, ListAPIView
from app.definitions.models import Schema


class SchemaSerializer(ApiSerializer):
id = serializers.SerializerMethodField()

tags = serializers.ListField(
child=serializers.CharField(max_length=30),
max_length=10,
allow_empty=True,
allow_null=True,
required=False,
)

class Meta:
model = Schema
fields = [
'id',
'name',
'tags',
'created_at',
'updated_at',
]
writable_fields = ['tags']

def get_id(self, obj):
return obj.object_id

def validate_tags(self, tags):
return list(set(tags)) if isinstance(tags, (list,)) else []

def update(self, instance, validated_data):
instance.tags = validated_data.get('tags', instance.tags)
instance.save()
return instance


class SchemaList(ListAPIView):
serializer_class = SchemaSerializer

def get_queryset(self):
filter_kwargs = {
'datastore_id': self.kwargs['datastore_id'],
'workspace': self.request.workspace,
}
return Schema.objects.filter(**filter_kwargs)


class SchemaDetail(DetailAPIView):
serializer_class = SchemaSerializer

def get_object(self, pk):
get_kwargs = {
'workspace': self.request.workspace,
'object_id': pk,
}
try:
return Schema.objects.get(**get_kwargs)
except Schema.DoesNotExist:
raise NotFound()


class SchemaFind(FindAPIView):
serializer_class = SchemaSerializer

required_query_params = ['name']

def find_object(self, datastore_id, query_params):
filter_kwargs = {
'datastore_id': datastore_id,
'workspace': self.request.workspace,
'name': query_params['name'],
}
return Schema.objects.filter(**filter_kwargs).first()
Loading

0 comments on commit 14f91ee

Please sign in to comment.