Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ repos:
rev: 21.12b0
hooks:
- id: black
additional_dependencies: [click==8.0.4]

- repo: https://github.com/PyCQA/isort
rev: 5.10.1
rev: 5.13.2
hooks:
- id: isort

- repo: https://github.com/PyCQA/flake8
rev: 4.0.1
rev: 7.1.1
hooks:
- id: flake8
args: ["--config=setup.cfg"]
Comment on lines 24 to 28
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The flake8 version has been upgraded from 4.0.1 to 7.1.1, which is a major version jump (3 major versions). This is a significant upgrade that may introduce new linting rules or behavior changes. Ensure that all team members are aware of this upgrade and that any new linting errors are addressed. Consider documenting this change in the PR description or migration notes.

Copilot uses AI. Check for mistakes.
Expand Down
16 changes: 8 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The **branch name** is your first opportunity to give your task context.

It is recommended to combine [**Github issues**](https://github.com/Coders-HQ/CodersHQ/issues) with a short description that describes the task resolved in this branch, for example: `Coders-HQ-portfolio/challenge-form` or `Coders-HQ-eventbrite/adding-api`.

If you don't have Github issue for you PR, then you may avoid the prefix, but keep in mind that more likely you have to create the issue first.
If you don't have Github issue for you PR, then you may avoid the prefix, but keep in mind that more likely you have to create the issue first.

## Commit your changes

Expand All @@ -34,17 +34,17 @@ Be sure to **request reviews** from the appropriate people. This might include t

## Getting a better review

**Draft pull requests** in allow you to create a pull request that is still a work in progress and not ready for review. This is useful when you want to share your changes with others but aren't quite ready to merge them or request immediate feedback.
**Draft pull requests** in allow you to create a pull request that is still a work in progress and not ready for review. This is useful when you want to share your changes with others but aren't quite ready to merge them or request immediate feedback.
https://github.blog/2019-02-14-introducing-draft-pull-requests/

Once your pull request has been reviewed, be sure to **respond** to any feedback you receive. This might involve making additional changes to your code, addressing questions or concerns, or simply thanking reviewers for their feedback.
Once your pull request has been reviewed, be sure to **respond** to any feedback you receive. This might involve making additional changes to your code, addressing questions or concerns, or simply thanking reviewers for their feedback.

By using the **re-request review** feature, you can prompt the reviewer to take another look at your changes and provide feedback if necessary.
By using the **re-request review** feature, you can prompt the reviewer to take another look at your changes and provide feedback if necessary.
https://github.blog/changelog/2019-02-21-re-request-review-on-a-pull-request/

The **CODEOWNERS** file in GitHub allows you to specify who is responsible for code in a specific part of your repository. You can use this file to automatically assign pull requests to the appropriate people or teams, and to ensure that the right people are notified when changes are made to certain files or directories.
The **CODEOWNERS** file in GitHub allows you to specify who is responsible for code in a specific part of your repository. You can use this file to automatically assign pull requests to the appropriate people or teams, and to ensure that the right people are notified when changes are made to certain files or directories.
https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners

We use **scheduled reminders** to Slack for abandoned pull requests to will receive reminders to the team's channel for PRs that are non-draft and have no activity for a couple of days.
https://docs.github.com/en/organizations/organizing-members-into-teams/managing-scheduled-reminders-for-your-team

Expand All @@ -56,10 +56,10 @@ When your pull request is approved, be sure to **merge it responsibly**. This mi

### For curious minds

- How to write a Git commit message:
- How to write a Git commit message:
https://cbea.ms/git-commit/

- 13 tips to make your PR easier to review:
- 13 tips to make your PR easier to review:
https://blog.codacy.com/13-tips-to-make-your-pr-easier-to-review/

Happy contributing!
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,4 @@ pro-collectstatic:
docker compose -f production.yml run --rm django python manage.py collectstatic

pro-rebuild:
make pro-down && git pull && make pro-build && make pro-up
make pro-down && git pull && make pro-build && make pro-up
44 changes: 31 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<img width="80" alt="MIT License Badge" src="https://img.shields.io/badge/License-MIT-red.svg">
</a>
<a href="https://discord.gg/CPQHAZrg8b0">
<img width="80" alt="Discord Server Badge" src="https://img.shields.io/badge/Discord-%237289DA.svg?style=for-the-badge&logo=discord&logoColor=white">
<img width="80" alt="Discord Server Badge" src="https://img.shields.io/badge/Discord-%237289DA.svg?style=for-the-badge&logo=discord&logoColor=white">
</a>
</p>

Expand All @@ -50,7 +50,7 @@


## :wave: Introduction

<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-9-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
Expand Down Expand Up @@ -80,12 +80,16 @@ We also document the tasks in [Notion](https://suwaidi.notion.site/Coders-HQ-ae1
## ⚙️ Quick Setup


> Note: The recommended command is `docker compose` (Docker Compose v2).
> If your environment only has `docker-compose`, substitute accordingly.


Make sure you have Docker version 2+ and then do the following to build the stack and update the databse :

$ docker-compose -f local.yml build
$ docker-compose -f local.yml run --rm django python manage.py makemigrations
$ docker-compose -f local.yml run --rm django python manage.py migrate
$ docker-compose -f local.yml run --rm django python manage.py createsuperuser
$ docker compose -f local.yml build
$ docker compose -f local.yml run --rm django python manage.py makemigrations
$ docker compose -f local.yml run --rm django python manage.py migrate
$ docker compose -f local.yml run --rm django python manage.py createsuperuser

Follow the rest of the README for more information and use ``/admin`` to edit and create challenges.

Expand Down Expand Up @@ -133,7 +137,7 @@ and might reappear if you generate a project multiple times with the same name.

This can take a while, especially the first time you run this particular command on your development system::

$ docker-compose -f local.yml build
$ docker compose -f local.yml build

Generally, if you want to emulate production environment use [`production.yml`](production.yml) instead. And this is true for any other actions you might need to perform: whenever a switch is required, just do it!

Expand All @@ -150,19 +154,19 @@ This brings up both Django and PostgreSQL. The first time it is run it might tak

Open a terminal at the project root and run the following for local development::

$ docker-compose -f local.yml up
$ docker compose -f local.yml up

You can also set the environment variable ``COMPOSE_FILE`` pointing to [`local.yml`](local.yml) like this::

$ export COMPOSE_FILE=local.yml

And then run::

$ docker-compose up
$ docker compose up

To run in a detached (background) mode, just::

$ docker-compose up -d
$ docker compose up -d

<div align="right">

Expand All @@ -173,10 +177,10 @@ To run in a detached (background) mode, just::
## Execute Management Commands


As with any shell command that we wish to run in our container, this is done using the ``docker-compose -f local.yml run --rm`` command: ::
As with any shell command that we wish to run in our container, this is done using the ``docker compose -f local.yml run --rm`` command: ::

$ docker-compose -f local.yml run --rm django python manage.py migrate
$ docker-compose -f local.yml run --rm django python manage.py createsuperuser
$ docker compose -f local.yml run --rm django python manage.py migrate
$ docker compose -f local.yml run --rm django python manage.py createsuperuser

Here, ``django`` is the target service we are executing the commands against.

Expand Down Expand Up @@ -262,6 +266,20 @@ Please check `cookiecutter-django Docker documentation` for more details how to

With MailHog running, to view messages that are sent by your application, open your browser and go to ``http://127.0.0.1:8025``

### API Authentication (JWT)

The API uses JWT authentication (SimpleJWT).

- Obtain tokens:
- `POST /api/token/` with JSON body `{"username": "<username>", "password": "<password>"}`
- Response includes `access` and `refresh`
- Use the access token on requests:
- `Authorization: Bearer <access>` (legacy clients may also use `Authorization: JWT <access>`)
- Refresh tokens:
- `POST /api/token/refresh/` with `{"refresh": "<refresh>"}`

For backwards compatibility, `POST /api-token-auth/` is still available and returns a `token` field.

## Stargazers ⭐

### Thanks to all of our `Stargazers` ⭐ 🔭 who are supporting CodersHQ project
Expand Down
25 changes: 14 additions & 11 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,15 @@ We also document the tasks in the `project`_ section and have a look at the `iss
Quick Setup
-----------

.. note:: The recommended command is ``docker compose`` (Docker Compose v2).
If your environment only has ``docker-compose``, substitute accordingly.

Make sure you have Docker version 2+ and then do the following to build the stack and update the databse ::

$ docker-compose -f local.yml build
$ docker-compose -f local.yml run --rm django python manage.py makemigrations
$ docker-compose -f local.yml run --rm django python manage.py migrate
$ docker-compose -f local.yml run --rm django python manage.py createsuperuser
$ docker compose -f local.yml build
$ docker compose -f local.yml run --rm django python manage.py makemigrations
$ docker compose -f local.yml run --rm django python manage.py migrate
$ docker compose -f local.yml run --rm django python manage.py createsuperuser

Follow the rest of the README for more information and use ``/admin`` to edit and create challenges.

Expand Down Expand Up @@ -80,7 +83,7 @@ Build the Stack

This can take a while, especially the first time you run this particular command on your development system::

$ docker-compose -f local.yml build
$ docker compose -f local.yml build

Generally, if you want to emulate production environment use ``production.yml`` instead. And this is true for any other actions you might need to perform: whenever a switch is required, just do it!

Expand All @@ -92,28 +95,28 @@ This brings up both Django and PostgreSQL. The first time it is run it might tak

Open a terminal at the project root and run the following for local development::

$ docker-compose -f local.yml up
$ docker compose -f local.yml up

You can also set the environment variable ``COMPOSE_FILE`` pointing to ``local.yml`` like this::

$ export COMPOSE_FILE=local.yml

And then run::

$ docker-compose up
$ docker compose up

To run in a detached (background) mode, just::

$ docker-compose up -d
$ docker compose up -d


Execute Management Commands
---------------------------

As with any shell command that we wish to run in our container, this is done using the ``docker-compose -f local.yml run --rm`` command: ::
As with any shell command that we wish to run in our container, this is done using the ``docker compose -f local.yml run --rm`` command: ::

$ docker-compose -f local.yml run --rm django python manage.py migrate
$ docker-compose -f local.yml run --rm django python manage.py createsuperuser
$ docker compose -f local.yml run --rm django python manage.py migrate
$ docker compose -f local.yml run --rm django python manage.py createsuperuser

Here, ``django`` is the target service we are executing the commands against.

Expand Down
25 changes: 25 additions & 0 deletions codershq/api/auth_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer


class LegacyTokenObtainView(APIView):
"""Backwards-compatible JWT endpoint.

Historically this project exposed `/api-token-auth/` (drf-jwt) which returned
`{"token": "..."}`. SimpleJWT returns `{access, refresh}`.

This view preserves the legacy response shape while also returning the
modern fields.
"""

permission_classes = [AllowAny]

def post(self, request, *args, **kwargs):
serializer = TokenObtainPairSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
tokens = serializer.validated_data
access = tokens.get("access")
refresh = tokens.get("refresh")
return Response({"token": access, "access": access, "refresh": refresh})
Comment thread
kamrankhan78694 marked this conversation as resolved.
52 changes: 29 additions & 23 deletions codershq/api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,62 +1,68 @@
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group, User
from django.contrib.auth.password_validation import validate_password
from djangosaml2idp.models import ServiceProvider
from rest_framework import serializers
from rest_framework.validators import UniqueValidator

from codershq.users.models import User
from codershq.portfolio.models import Portfolio

User=get_user_model() # to point to the custom user model
User = get_user_model()


class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ['url', 'username', 'email', 'groups','id']
fields = ["url", "username", "email", "groups", "id"]


class PortfolioSerializer(serializers.ModelSerializer):
class Meta:
model = Portfolio
fields = '__all__'
fields = "__all__"


class RegisterSerializer(serializers.ModelSerializer):

email = serializers.EmailField(
required=True,
validators=[UniqueValidator(queryset=User.objects.all())]
)
required=True, validators=[UniqueValidator(queryset=User.objects.all())]
)

password = serializers.CharField(write_only=True, required=True, validators=[validate_password])
password = serializers.CharField(
write_only=True, required=True, validators=[validate_password]
)
password2 = serializers.CharField(write_only=True, required=True)



class Meta:
model = User
fields = ('username', 'password', 'password2', 'email', 'first_name', 'last_name')
fields = (
"username",
"password",
"password2",
"email",
"first_name",
"last_name",
)
extra_kwargs = {
'first_name': {'required': True},
'last_name': {'required': True}
"first_name": {"required": True},
"last_name": {"required": True},
}

def validate(self, attrs):
if attrs['password'] != attrs['password2']:
raise serializers.ValidationError({"password": "Password fields didn't match."})
if attrs["password"] != attrs["password2"]:
raise serializers.ValidationError(
{"password": "Password fields didn't match."}
)

return attrs

def create(self, validated_data):
user = User.objects.create(
username=validated_data['username'],
email=validated_data['email'],
first_name=validated_data['first_name'],
last_name=validated_data['last_name']
username=validated_data["username"],
email=validated_data["email"],
first_name=validated_data["first_name"],
last_name=validated_data["last_name"],
)


user.set_password(validated_data['password'])
user.set_password(validated_data["password"])
user.save()

return user
Loading