Skip to content

Commit

Permalink
Merge pull request #241 from napse-invest/docs
Browse files Browse the repository at this point in the history
Docs
  • Loading branch information
Xenepix authored Dec 21, 2023
2 parents 4fead4b + af6929a commit 4b2e28d
Show file tree
Hide file tree
Showing 20 changed files with 135 additions and 225 deletions.
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ all: setup-testing-environment makemigrations migrate runserver

setup:
ifeq ($(OS),Darwin) # Mac OS X
./setup-osx.sh
./setup/setup-osx.sh
else ifeq ($(OS),Linux)
./setup-unix.sh
./setup/setup-unix.sh
else
./setup-windows.sh
./setup/setup-windows.sh
endif

setup-testing-environment:
Expand Down
42 changes: 12 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,47 +22,29 @@

<p align="center">
<a href="#django-napse"><strong>Django Napse</strong></a> ·
<a href="#usefull-commands"><strong>Usefull commands</strong></a> .
<a href="#documentation"><strong>Documentation</strong></a> .
<a href="#how-to-contribute"><strong>How to contribute</strong></a>
</p>
<br/>

## django-napse
....

## Useful commands
Unless otherwise specified, all commands are to be run at the root folder of the project.
Django napse is a portfolio management module using trading bots.
This directory can be used as a django module, which you can install as follows:

### Create a new project
- Unix \
```source setup-unix.sh```

- Windows \
```.\setup-windows.ps1```
```bash
pip install django-napse
```

### Run a test version of the project
Or you can use it as a local backend for the [Napse desktop application](https://github.com/napse-invest/Napse), by cloning the repository.

- Build migrations \
```make makemigrations```
- Apply migrations \
```make migrate```
- Run server \
```make runserver```
Find more details for installation in the [documentation](https://napse-invest.github.io/django-napse/#installation).

### Run coverage tests
### Documentation

- Run tests \
```test-napse```
- Run tests with coverage \
```coverage```
- Run tests with coverage and open coverage report \
```coverage-open```
You can find the documentation [here](https://napse-invest.github.io/django-napse/).

## Documentation

[Docs](https://napse-invest.github.io/django-napse/)
## How to contribute

Run mkdocs server:
```
make mkdocs
```
If you want to contribute to the project, please read the [contributing guidelines](https://napse-invest.github.io/django-napse/contributing/) first. You will find the setup instructions and our standards.
1 change: 1 addition & 0 deletions django_napse/api/fleets/serializers/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from .cluster_serialisers import ClusterSerializer
from .fleet_serializers import FleetDetailSerializer, FleetSerializer
17 changes: 17 additions & 0 deletions django_napse/api/fleets/serializers/cluster_serialisers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from rest_framework import serializers

from django_napse.api.bots.serializers import BotSerializer
from django_napse.core.models import Cluster


class ClusterSerializer(serializers.ModelSerializer):
template_bot = BotSerializer()

class Meta:
model = Cluster
fields = [
"template_bot",
"share",
"breakpoint",
"autoscale",
]
8 changes: 6 additions & 2 deletions django_napse/api/fleets/serializers/fleet_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@
from rest_framework.fields import empty

from django_napse.api.bots.serializers import BotSerializer
from django_napse.api.fleets.serializers.cluster_serialisers import ClusterSerializer
from django_napse.core.models import ConnectionWallet, Fleet


class FleetSerializer(serializers.ModelSerializer):
value = serializers.SerializerMethodField(read_only=True)
bot_count = serializers.SerializerMethodField(read_only=True)
clusters = ClusterSerializer(
write_only=True,
many=True,
required=True,
)

class Meta:
model = Fleet
Expand All @@ -20,8 +26,6 @@ class Meta:
]
read_only_fields = [
"uuid",
"value",
"bot_count",
]

def __init__(self, instance=None, data=empty, space=None, **kwargs):
Expand Down
15 changes: 13 additions & 2 deletions django_napse/api/fleets/views/fleet_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@
from django_napse.api.custom_permissions import HasSpace
from django_napse.api.custom_viewset import CustomViewSet
from django_napse.api.fleets.serializers import FleetDetailSerializer, FleetSerializer
from django_napse.core.models import NapseSpace
from django_napse.core.models import Fleet, NapseSpace


class FleetView(CustomViewSet):
permission_classes = [HasAPIKey, HasSpace]
serializer_class = FleetSerializer

def get_queryset(self):
self.space = NapseSpace.objects.get(uuid=self.request.query_params["space"])
space_uuid = self.request.query_params.get("space", None)
if space_uuid is None:
return Fleet.objects.all()
self.space = NapseSpace.objects.get(uuid=space_uuid)
return self.space.fleets

def get_serialiser_class(self, *args, **kwargs):
Expand All @@ -25,6 +28,13 @@ def get_serialiser_class(self, *args, **kwargs):
result = actions.get(self.action)
return result if result else super().get_serializer_class()

def get_permissions(self):
match self.action:
case "list" | "create":
return [HasAPIKey()]
case _:
return super().get_permissions()

def list(self, request):
serializer = self.serializer_class(self.get_queryset(), many=True, space=self.space)
return Response(serializer.data, status=status.HTTP_200_OK)
Expand All @@ -34,6 +44,7 @@ def retrieve(self, request, pk=None):

def create(self, request, *args, **kwargs):
return Response(status=status.HTTP_501_NOT_IMPLEMENTED)
# serializer = self.serializer_class(data=request.data, space=self.space)

def delete(self):
return Response(status=status.HTTP_501_NOT_IMPLEMENTED)
14 changes: 2 additions & 12 deletions django_napse/api/spaces/views/space_view.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework_api_key.permissions import HasAPIKey

from django_napse.api.custom_permissions import HasFullAccessPermission, HasMasterKey, HasReadPermission
from django_napse.api.custom_viewset import CustomViewSet
from django_napse.api.exchanges.serializers.exchange_account_serializer import ExchangeAccountSerializer
from django_napse.api.spaces.serializers import SpaceDetailSerializer, SpaceSerializer
from django_napse.core.models import ExchangeAccount, NapseSpace
from django_napse.core.models import NapseSpace
from django_napse.utils.errors import SpaceError


Expand Down Expand Up @@ -38,7 +36,7 @@ def get_permissions(self):
return [HasReadPermission()]
case "list":
return [HasAPIKey()]
case "possible_exchange_accounts" | "create":
case "create":
return [HasMasterKey()]

case _:
Expand Down Expand Up @@ -82,11 +80,3 @@ def delete(self, request, *args, **kwargs):
except SpaceError.DeleteError:
return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
return Response(status=status.HTTP_204_NO_CONTENT)

@action(detail=False, methods=["GET"])
def possible_exchange_accounts(self, request):
serialized_exchange_account = ExchangeAccountSerializer(ExchangeAccount.objects.all(), many=True)
return Response(
serialized_exchange_account.data,
status=status.HTTP_200_OK,
)
12 changes: 10 additions & 2 deletions django_napse/core/models/fleets/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,16 @@


class Cluster(models.Model):
fleet = models.ForeignKey("Fleet", on_delete=models.CASCADE, related_name="clusters")
template_bot = models.OneToOneField("Bot", on_delete=models.CASCADE, related_name="cluster")
fleet = models.ForeignKey(
"Fleet",
on_delete=models.CASCADE,
related_name="clusters",
)
template_bot = models.OneToOneField(
"Bot",
on_delete=models.CASCADE,
related_name="cluster",
)
share = models.FloatField()
breakpoint = models.FloatField()
autoscale = models.BooleanField()
Expand Down
21 changes: 17 additions & 4 deletions django_napse/core/models/fleets/fleet.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,25 @@


class Fleet(models.Model):
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
name = models.CharField(max_length=100, default="Fleet")
exchange_account = models.ForeignKey("ExchangeAccount", on_delete=models.CASCADE)
uuid = models.UUIDField(
default=uuid.uuid4,
editable=False,
unique=True,
)
name = models.CharField(
max_length=100,
default="Fleet",
)
exchange_account = models.ForeignKey(
"ExchangeAccount",
on_delete=models.CASCADE,
)
running = models.BooleanField(default=False)
setup_finished = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True, blank=True)
created_at = models.DateTimeField(
auto_now_add=True,
blank=True,
)

objects = FleetManager()

Expand Down
26 changes: 13 additions & 13 deletions django_napse/utils/api_test_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,42 +96,42 @@ def run_tests(self, mode):
self.check_auth(name="No permissions", mode=mode, error_list=error_list, divider=100, expected=2)
else:
if HasSpace in permissions:
self.check_auth(name="HasSpace \w no key", mode=mode, error_list=error_list, expected=400)
self.check_auth(name="HasSpace with no key", mode=mode, error_list=error_list, expected=400)
self.build_url(kwargs={"space": str("random uuid"), **self.kwargs})
self.check_auth(name="HasSpace \w no key", mode=mode, error_list=error_list, expected=400)
self.check_auth(name="HasSpace with no key", mode=mode, error_list=error_list, expected=400)
self.build_url(kwargs={"space": str("7aafc68d-f619-4874-aaf5-c123a176e303"), **self.kwargs})
self.check_auth(name="HasSpace \w no key", mode=mode, error_list=error_list, expected=400)
self.check_auth(name="HasSpace with no key", mode=mode, error_list=error_list, expected=400)
self.build_url(kwargs={"space": str(self.space.uuid), **self.kwargs})

if HasAPIKey in permissions:
self.check_auth(name="HasAPIKey \w no key", mode=mode, error_list=error_list)
self.check_auth(name="HasAPIKey with no key", mode=mode, error_list=error_list)

if HasReadPermission in permissions:
self.check_auth(name="HasReadPermission \w no key", mode=mode, error_list=error_list)
self.check_auth(name="HasReadPermission with no key", mode=mode, error_list=error_list)
self.build_key([])
self.authenticate()
self.check_auth(name="HasReadPermission \w no permissions", mode=mode, error_list=error_list)
self.check_auth(name="HasReadPermission with no permissions", mode=mode, error_list=error_list)

if HasFullAccessPermission in permissions:
self.check_auth(name="HasFullAccessPermission \w no key", mode=mode, error_list=error_list)
self.check_auth(name="HasFullAccessPermission with no key", mode=mode, error_list=error_list)
self.build_key([])
self.authenticate()
self.check_auth(name="HasFullAccessPermission \w no permissions", mode=mode, error_list=error_list)
self.check_auth(name="HasFullAccessPermission with no permissions", mode=mode, error_list=error_list)
self.build_key([HasReadPermission])
self.authenticate()
self.check_auth(name="HasFullAccessPermission \w read permissions", mode=mode, error_list=error_list)
self.check_auth(name="HasFullAccessPermission with read permissions", mode=mode, error_list=error_list)

if HasAdminPermission in permissions:
self.check_auth(name="HasAdminPermission \w no key", mode=mode, error_list=error_list)
self.check_auth(name="HasAdminPermission with no key", mode=mode, error_list=error_list)
self.build_key([])
self.authenticate()
self.check_auth(name="HasAdminPermission \w no permissions", mode=mode, error_list=error_list)
self.check_auth(name="HasAdminPermission with no permissions", mode=mode, error_list=error_list)
self.build_key([HasReadPermission])
self.authenticate()
self.check_auth(name="HasAdminPermission \w read permissions", mode=mode, error_list=error_list)
self.check_auth(name="HasAdminPermission with read permissions", mode=mode, error_list=error_list)
self.build_key([HasReadPermission, HasFullAccessPermission])
self.authenticate()
self.check_auth(name="HasAdminPermission \w read and full access permissions", mode=mode, error_list=error_list)
self.check_auth(name="HasAdminPermission with read and full access permissions", mode=mode, error_list=error_list)

self.build_key(permissions)
self.authenticate()
Expand Down
14 changes: 11 additions & 3 deletions docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,19 @@ You can commit the code from your fork through a pull request on the official re
=== "Linux"

```bash
source setup-unix.sh
source setup/setup-unix.sh
```

=== "MacOS"

```bash
source setup/setup-osx.sh
```

=== "Windows"

```powershell
.\setup-windows.ps1
.\setup\setup-windows.ps1
```

#### Setup initial exchange accounts
Expand All @@ -89,9 +95,11 @@ At `tests/test_app/`, build a `secret.json` file (or run the `./setup_secrets.sh
}
}
}

```

!!! note
We **strongly recommend** to add the `secret.json` file to your `.gitignore` file to avoid sharing your API keys.

#### Run

```bash
Expand Down
Loading

0 comments on commit 4b2e28d

Please sign in to comment.