Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions backend/apps/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""OWASP API."""
1 change: 1 addition & 0 deletions backend/apps/api/admin/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .api_key import ApiKeyAdmin
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""Nest app APIKey model admin."""
"""API key model admin."""

from django.contrib import admin

from apps.nest.models.api_key import ApiKey
from apps.api.models.api_key import ApiKey


class ApiKeyAdmin(admin.ModelAdmin):
Expand Down
9 changes: 9 additions & 0 deletions backend/apps/api/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""API app config."""

from django.apps import AppConfig


class ApiConfig(AppConfig):
"""API app config."""

name = "apps.api"
10 changes: 10 additions & 0 deletions backend/apps/api/internal/mutations/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""API app mutations."""

import strawberry

from .api_key import ApiKeyMutations


@strawberry.type
class ApiMutations(ApiKeyMutations):
"""API mutations."""
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Nest API key api.internal Mutations."""
"""API app mutations."""

import logging
from datetime import datetime
Expand All @@ -9,9 +9,9 @@
from django.utils import timezone
from strawberry.types import Info

from apps.nest.api.internal.nodes.api_key import ApiKeyNode
from apps.api.internal.nodes.api_key import ApiKeyNode
from apps.api.models.api_key import MAX_ACTIVE_KEYS, MAX_WORD_LENGTH, ApiKey
from apps.nest.api.internal.permissions import IsAuthenticated
from apps.nest.models.api_key import MAX_ACTIVE_KEYS, MAX_WORD_LENGTH, ApiKey

logger = logging.getLogger(__name__)

Expand All @@ -38,7 +38,7 @@ class CreateApiKeyResult:

@strawberry.type
class ApiKeyMutations:
"""api.internal mutation class for API keys."""
"""API key mutations."""

@strawberry.mutation(permission_classes=[IsAuthenticated])
def create_api_key(self, info: Info, name: str, expires_at: datetime) -> CreateApiKeyResult:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import strawberry
import strawberry_django

from apps.nest.models.api_key import ApiKey
from apps.api.models.api_key import ApiKey


@strawberry_django.type(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import strawberry

from apps.nest.api.internal.queries.api_key import ApiKeyQueries
from apps.api.internal.queries.api_key import ApiKeyQueries


@strawberry.type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import strawberry
from strawberry.types import Info

from apps.nest.api.internal.nodes.api_key import ApiKeyNode
from apps.api.internal.nodes.api_key import ApiKeyNode
from apps.nest.api.internal.permissions import IsAuthenticated


Expand Down
50 changes: 50 additions & 0 deletions backend/apps/api/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Generated by Django 5.2.5 on 2025-09-09 23:41

import uuid

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):
initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name="ApiKey",
fields=[
(
"id",
models.BigAutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("expires_at", models.DateTimeField()),
("hash", models.CharField(max_length=64, unique=True)),
("is_revoked", models.BooleanField(default=False)),
("last_used_at", models.DateTimeField(blank=True, null=True)),
("name", models.CharField(max_length=100)),
("uuid", models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="api_keys",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"verbose_name_plural": "API keys",
"db_table": "api_keys",
"ordering": ["-created_at"],
},
),
]
1 change: 1 addition & 0 deletions backend/apps/api/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .api_key import ApiKey
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Nest app API key model."""
"""API key model."""

import hashlib
import secrets
Expand All @@ -17,7 +17,7 @@ class ApiKey(models.Model):
"""API key model."""

class Meta:
db_table = "nest_api_keys"
db_table = "api_keys"
verbose_name_plural = "API keys"
ordering = ["-created_at"]

Expand Down
1 change: 1 addition & 0 deletions backend/apps/api/rest/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""OWASP REST API."""
1 change: 1 addition & 0 deletions backend/apps/api/rest/auth/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""OWASP REST API."""
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
from ninja.errors import HttpError
from ninja.security import APIKeyHeader

from apps.nest.models.api_key import ApiKey
from apps.api.models.api_key import ApiKey


class ApiKeyAuth(APIKeyHeader):
class ApiKeyHeader(APIKeyHeader):
"""Custom API key authentication class for Ninja."""

param_name = "X-API-Key"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,51 @@
"""OWASP Nest API v1 configuration."""
"""OWASP REST API v0."""

from django.conf import settings
from ninja import NinjaAPI, Swagger
from ninja.throttling import AuthRateThrottle

from apps.core.api.ninja import ApiKeyAuth
from apps.github.api.rest.v1.issue import router as issue_router
from apps.github.api.rest.v1.member import router as member_router
from apps.github.api.rest.v1.organization import router as organization_router
from apps.github.api.rest.v1.release import router as release_router
from apps.github.api.rest.v1.repository import router as repository_router
from apps.owasp.api.rest.v1.chapter import router as chapter_router
from apps.owasp.api.rest.v1.committee import router as committee_router
from apps.owasp.api.rest.v1.event import router as event_router
from apps.owasp.api.rest.v1.project import router as project_router
from apps.api.rest.auth.api_key import ApiKeyHeader
from apps.api.rest.v0.committee import router as committee_router
from apps.api.rest.v0.event import router as event_router
from apps.api.rest.v0.issue import router as issue_router
from apps.api.rest.v0.member import router as member_router
from apps.api.rest.v0.organization import router as organization_router
from apps.api.rest.v0.project import router as project_router
from apps.api.rest.v0.release import router as release_router
from apps.api.rest.v0.repository import router as repository_router

from .chapter import router as chapter_router

ROUTERS = {
# Chapters.
"/chapters": chapter_router,
# Committees.
"/committees": committee_router,
# Community.
"/members": member_router,
"/organizations": organization_router,
# Events.
"/events": event_router,
# Issues.
"/issues": issue_router,
# Projects.
"/projects": project_router,
# Releases.
"/releases": release_router,
# Repositories.
"/repositories": repository_router,
}


api_settings = {
"auth": ApiKeyAuth(),
"auth": ApiKeyHeader(),
"description": "Open Worldwide Application Security Project API",
"docs": Swagger(settings={"persistAuthorization": True}),
"throttle": [AuthRateThrottle("10/s")],
"title": "OWASP Nest",
"version": "1.0.0",
"version": "0.1.3",
}


api_settings_customization = {}
if settings.IS_LOCAL_ENVIRONMENT:
api_settings_customization = {
Expand Down Expand Up @@ -56,38 +77,17 @@
],
}


api = NinjaAPI(**{**api_settings, **api_settings_customization})


@api.get("/", include_in_schema=False)
def api_root(request):
"""Handle API root endpoint requests."""
return {
"message": "Welcome to the OWASP Nest API v1",
"message": "Welcome to the OWASP Nest API v0",
"docs_url": request.build_absolute_uri("docs"),
}


ROUTERS = {
# Chapters.
"/chapters": chapter_router,
# Committees.
"/committees": committee_router,
# Community.
"/members": member_router,
"/organizations": organization_router,
# Events.
"/events": event_router,
# Issues.
"/issues": issue_router,
# Projects.
"/projects": project_router,
# Releases.
"/releases": release_router,
# Repositories.
"/repositories": repository_router,
}

for prefix, router in ROUTERS.items():
api.add_router(prefix, router)
1 change: 0 additions & 1 deletion backend/apps/github/api/rest/__init__.py

This file was deleted.

1 change: 0 additions & 1 deletion backend/apps/github/api/rest/v1/__init__.py

This file was deleted.

1 change: 0 additions & 1 deletion backend/apps/nest/admin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Nest app admin."""

from .api_key import ApiKeyAdmin
from .badge import BadgeAdmin
from .user import UserAdmin
from .user_badge import UserBadgeAdmin
3 changes: 1 addition & 2 deletions backend/apps/nest/api/internal/mutations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

import strawberry

from .api_key import ApiKeyMutations
from .user import UserMutations


@strawberry.type
class NestMutations(ApiKeyMutations, UserMutations):
class NestMutations(UserMutations):
"""Nest mutations."""
15 changes: 15 additions & 0 deletions backend/apps/nest/migrations/0006_delete_apikey.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Generated by Django 5.2.5 on 2025-09-09 23:41

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("nest", "0005_alter_userbadge_user"),
]

operations = [
migrations.DeleteModel(
name="ApiKey",
),
]
1 change: 0 additions & 1 deletion backend/apps/nest/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from .api_key import ApiKey
from .badge import Badge
from .user import User
from .user_badge import UserBadge
2 changes: 1 addition & 1 deletion backend/apps/nest/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
if TYPE_CHECKING:
from django.db.models import QuerySet

from apps.nest.models.api_key import ApiKey
from apps.api.models.api_key import ApiKey


class User(AbstractUser):
Expand Down
1 change: 0 additions & 1 deletion backend/apps/owasp/api/rest/__init__.py

This file was deleted.

1 change: 0 additions & 1 deletion backend/apps/owasp/api/rest/v1/__init__.py

This file was deleted.

9 changes: 5 additions & 4 deletions backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,6 @@ lint.per-file-ignores."**/migrations/*.py" = [
lint.per-file-ignores."**/models/*.py" = [
"D106", # https://docs.astral.sh/ruff/rules/undocumented-public-nested-class/
]
lint.per-file-ignores."**/rest/v1/*.py" = [
"ARG001", # https://docs.astral.sh/ruff/rules/unused-function-argument/
"B008", # https://docs.astral.sh/ruff/rules/function-call-in-default-argument/
]
lint.per-file-ignores."**/settings/*.py" = [
"RUF012", # https://docs.astral.sh/ruff/rules/mutable-class-default/
]
Expand All @@ -120,6 +116,11 @@ lint.per-file-ignores."**/tests/**/*.py" = [
"SLF001", # https://docs.astral.sh/ruff/rules/private-member-access/
]

lint.per-file-ignores."apps/api/rest/**/*.py" = [
"ARG001", # https://docs.astral.sh/ruff/rules/unused-function-argument/
"B008", # https://docs.astral.sh/ruff/rules/function-call-in-default-argument/
]

[tool.pytest.ini_options]
DJANGO_CONFIGURATION = "Test"
DJANGO_SETTINGS_MODULE = "settings.test"
Expand Down
1 change: 0 additions & 1 deletion backend/settings/api/__init__.py

This file was deleted.

1 change: 1 addition & 0 deletions backend/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class Base(Configuration):

LOCAL_APPS = (
"apps.ai",
"apps.api",
"apps.common",
"apps.core",
"apps.github",
Expand Down
Loading