Skip to content

Commit

Permalink
Merge pull request #213 from johnpooch/develop
Browse files Browse the repository at this point in the history
v0.3
  • Loading branch information
johnpooch authored Apr 22, 2021
2 parents 6c3d6e3 + 194957b commit caf2cee
Show file tree
Hide file tree
Showing 18 changed files with 306 additions and 48 deletions.
40 changes: 27 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,22 @@ fans.

This project consists of the following main components:

* `core` - This is the [Django][django] app that powers the project's back end.
- `core` - This is the [Django][django] app that powers the project's back end.
This is where the models are defined. All functionality relating to the
database lives here.

* `adjudicator` - In diplomacy, at the end of every turn the orders that each
- `adjudicator` - In diplomacy, at the end of every turn the orders that each
player has submitted are interpreted and the board is updated. `adjudicator`
is a python package which interprets an in-game turn and returns the outcome
of the orders. The outcome is then interpreted by `core` and the state of the
game is updated accordingly.

* `service` - This is a [Django Rest Framework][DRF] app that provides the API
- `service` - This is a [Django Rest Framework][drf] app that provides the API
through which the `client` application can interact with `core`.

* `client` - This is [React JS][reactjs] app that acts as the front end of the
- `client` - This is [React JS][reactjs] app that acts as the front end of the
project. The client app is contained in a [separate repo][client].


## Getting started

These instructions will get you started with a copy of the project up on your
Expand All @@ -50,14 +49,14 @@ development. Follow the docs to get Docker and Docker Compose installed.
Run the following commands from the root directory to create local copies of
configuration files:

* Run `cp project/settings/local.example.py project/settings/local.py`
* Run `cp docker-compose.override.example.yml docker-compose.override.yml`
- Run `cp project/settings/local.example.py project/settings/local.py`
- Run `cp docker-compose.override.example.yml docker-compose.override.yml`

#### Bring up local copy

* Run `docker-compose up` to bring up the project (You can run detached by
- Run `docker-compose up` to bring up the project (You can run detached by
adding `-d` flag)
* Once the containers are up you can run commands from inside the docker
- Once the containers are up you can run commands from inside the docker
service container by running `docker exec -it diplomacy_diplomacy.service_1`
and then running whatever command you like.

Expand All @@ -66,10 +65,12 @@ configuration files:
To load the fixtures run `make reset_db && make dev_fixtures && make superuser` from the root directory
(outside container). This resets the database, builds the fixtures in
`fixtures/dev` and creates a superuser with the following credentials:

```
Username: admin
Pw: admin
```

You can sign into the client and the service using these credentials.

### Non-docker set up
Expand All @@ -78,15 +79,18 @@ You can sign into the client and the service using these credentials.

#### Prerequisites

Ensure that you have installed `virtualenv` and `make`.
Ensure that you have installed `virtualenv`, `rabbitmq`, and `make`.

#### Virtual environent

Create a virtual environment:

```
python -m virtualenv venv
```

Activate the virtual environment:

```
# Unix
source venv/bin/activate
Expand All @@ -97,6 +101,7 @@ venv\Scripts\activate.bat
```

Install requirements:

```
pip install --user -r requirements.txt -r dev_requirements.txt
```
Expand All @@ -105,6 +110,7 @@ pip install --user -r requirements.txt -r dev_requirements.txt

Run the following command from the root directory to create local copies of
configuration files:

```
# Unix
cp project/settings/local.example.py project/settings/local.py
Expand All @@ -118,6 +124,7 @@ Open the `local.py` file and edit uncomment each section labeled "non Docker set
#### Bring up development server

Run the development server on port 8082. This is what the client expects during deevelopment.

```
# Unix
python ./manage.py runserver localhost:8082
Expand All @@ -130,12 +137,20 @@ python .\manage.py runserver localhost:8082

To load the fixtures run `make fixtures_local` from the root directory. This builds the fixtures in
`fixtures/dev` and creates a superuser with the following credentials:

```
Username: admin
Pw: admin
```

You can sign into the client and the service using these credentials.

#### Bring up rabbitmq worker

You must bring up a rabbitmq instance to enable celery tasks. This is required by
`models.TurnManager.new` which create a `models.TurnEnd` instance.

On windows you can install rabbitmq using `choco install rabbitmq`. Once installed, a rabbitmq instance is automatically started on the port specified in `settings/local.example.py`.

## Running the tests

Expand All @@ -148,13 +163,12 @@ root. If there are code style problems they will be displayed.

## Test Coverage

To generate a test coverage report test coverage, run `coverage run manage.py
test` from within the container. Then run `coverage report` to see the results.
To generate a test coverage report test coverage, run `coverage run manage.py test` from within the container. Then run `coverage report` to see the results.

[play diplomacy]: https://www.playdiplomacy.com/
[backstabbr]: https://www.backstabbr.com/
[django]: https://www.djangoproject.com/
[DRF]: https://www.django-rest-framework.org/
[drf]: https://www.django-rest-framework.org/
[reactjs]: https://www.reactjs.org/
[client]: https://www.github.com/samjhayes/diplomacy-client/
[docker]: https://docs.docker.com/
Expand Down
24 changes: 20 additions & 4 deletions accounts/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ class RegisterSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email', 'password')
extra_kwargs = {'password': {'write_only': True}}
extra_kwargs = {
'email': {'required': True},
'password': {'write_only': True}
}

def create(self, validated_data):
user = User.objects.create_user(
Expand All @@ -27,18 +30,31 @@ def create(self, validated_data):
)
return user

def validate_password(self, password):
email = self.initial_data.get('email')
username = self.initial_data.get('username')
temp_user = User(email=email, username=username)
validate_password(password, temp_user)


class LoginSerializer(serializers.Serializer):
username = serializers.CharField()
email = serializers.EmailField(required=False)
username = serializers.CharField(required=False)
password = serializers.CharField()

def validate(self, data):
email = data.get('email')
username = data.get('username')
if not (email or username):
raise serializers.ValidationError(
'Must provide either email or username. Please try again.'
)
user = authenticate(**data)
if user and user.is_active:
return user
raise serializers.ValidationError(
'The username or password you entered do not match an account. '
'Please try again.'
'The {} or password you entered do not match an account. '
'Please try again.'.format('username' if username else 'email')
)


Expand Down
26 changes: 23 additions & 3 deletions accounts/api/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import re

from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from knox.models import AuthToken
Expand All @@ -7,6 +9,9 @@
from . import serializers


EMAIL_REGEX = r'^(\w|\.|\_|\-)+[@](\w|\_|\-|\.)+[.]\w{2,3}$'


class UserAPIView(generics.RetrieveAPIView):
serializer_class = serializers.UserSerializer
permission_classes = [
Expand All @@ -33,13 +38,28 @@ def post(self, request, *args, **kwargs):
class LoginAPIView(generics.GenericAPIView):
serializer_class = serializers.LoginSerializer

@staticmethod
def is_using_email(request):
username = request.data.get('username')
return username and re.search(EMAIL_REGEX, username)

def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)

# Allow username to be username or email
using_email = self.is_using_email(request)
login_kwarg = 'email' if using_email else 'username'
data = {
login_kwarg: request.data.get('username'),
'password': request.data.get('password')
}

serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data
user_data = serializers.UserSerializer(user).data
return Response({
"user": serializers.UserSerializer(user, context=self.get_serializer_context()).data,
"token": AuthToken.objects.create(user)[1]
'user': user_data,
'token': AuthToken.objects.create(user)[1]
})


Expand Down
Loading

0 comments on commit caf2cee

Please sign in to comment.