Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0ed1b94
test!
kaye-s Feb 11, 2026
69a3118
Jacob Test
JacobLind1 Feb 11, 2026
3860278
tim
TingEnChang Feb 11, 2026
99a712e
connect openAI api to backend
TingEnChang Feb 12, 2026
3b4c170
connet frontend-backend-openai api
TingEnChang Feb 13, 2026
0ae235d
database connected to enviornment
kaye-s Feb 16, 2026
5f3d3fa
database secrets preserved
kaye-s Feb 18, 2026
d85a13a
Revert "database connected to enviornment"
kaye-s Feb 18, 2026
8377edc
OKAY NOW FIXED, be sure to get .env file updated with new credentials
kaye-s Feb 18, 2026
012e418
showuser add user database functionality linked up
kaye-s Feb 18, 2026
c7beafb
password hashing
kaye-s Feb 18, 2026
a6c2e34
Moved db queries to new html file
kaye-s Feb 18, 2026
8ee5c87
Initial backend commit: barebones backend inside app folder GroupFive…
JacobLind1 Feb 18, 2026
4ad8843
Merge pull request #2 from kaye-s/AI-api
kaye-s Feb 18, 2026
d74cf23
Frontend UI
NathanEdwards2023 Feb 19, 2026
7105115
Merge branch 'master' into frontend
kaye-s Feb 19, 2026
f4428c8
Merge pull request #3 from kaye-s/frontend
kaye-s Feb 19, 2026
81d21e1
Merge pull request #4 from kaye-s/backendtoo
kaye-s Feb 19, 2026
566263f
Merge branch 'master' into postgres
kaye-s Feb 19, 2026
0ca13c8
Merge pull request #1 from kaye-s/postgres
kaye-s Feb 19, 2026
5c156bb
Renamed API folder. Fixed urls.py and api/urls.py to pass initial tes…
JacobLind1 Feb 22, 2026
ecc43b5
api/urls.py
JacobLind1 Feb 22, 2026
80a832f
Database Integrated with Backend, Added Requirements I had forgotten.…
JacobLind1 Feb 22, 2026
2a92970
Fixed issue connecting with group database.
JacobLind1 Mar 4, 2026
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ profile_default/
ipython_config.py

# pyenv
#don't add database credentials
.env
.python-version

# pipenv
Expand Down Expand Up @@ -189,3 +191,4 @@ gradle-app.setting

/.vs/
node_modules/
.env
Empty file added api/__init__.py
Empty file.
3 changes: 3 additions & 0 deletions api/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.
6 changes: 6 additions & 0 deletions api/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class OurApplicationConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'api'
13 changes: 13 additions & 0 deletions api/dummy_analysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

def run_dummy(code, language):

return {
"summary" : "this dummy code is better than yours",
"findings" : [
{
"severity" : "Minimal",
"description" : "Bad code",
"fix" : "Figure it Out"
}
]
}
30 changes: 30 additions & 0 deletions api/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 5.0.3 on 2026-02-18 09:51

import django.db.models.deletion
import uuid
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='AnalysisTask',
fields=[
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('input_code', models.TextField()),
('language', models.CharField(max_length=50)),
('status', models.CharField(choices=[('QUEUED', 'Queued'), ('RUNNING', 'Running'), ('COMPLETED', 'Completed'), ('FAILED', 'Failed')], max_length=20)),
('results', models.JSONField(blank=True, null=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]
Empty file added api/migrations/__init__.py
Empty file.
21 changes: 21 additions & 0 deletions api/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#all id related lines are noted and can be deleted or changed if user id is skipped or substituted
import uuid #for user ID
from django.db import models
from django.contrib.auth.models import User

class AnalysisTask(models.Model):
#potential review request statuses
STATUS_OPT = [
("QUEUED", "Queued"),
("RUNNING", "Running"),
("COMPLETED", "Completed"),
("FAILED", "Failed")
]

id = models.UUIDField(primary_key=True, default=uuid.uuid4) #more user id
user = models.ForeignKey(User, on_delete=models.CASCADE) #user id/user
input_code = models.TextField() #user provided code
language = models.CharField(max_length=50) #language of user provided code
status = models.CharField(max_length=20, choices=STATUS_OPT) #status of review request
results = models.JSONField(null=True, blank=True) #results of review
created_at = models.DateTimeField(auto_now_add=True) #creation timestamp
7 changes: 7 additions & 0 deletions api/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#this file uses serializers to define what information we add to our AnalysisTask model from user
from rest_framework import serializers

class AnalysisRequestSerializer(serializers.Serializer):
code = serializers.CharField() #for input code
#language definition of input code, can be commented out if language distinction added later
language = serializers.CharField()
22 changes: 22 additions & 0 deletions api/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#from celery import shared_task #task queue to handle simultaneous requests, making testing annoying for now can readd later when necessary
from api.models import AnalysisTask
from .dummy_analysis import run_dummy

#@shared_task --from celery, readd later
def run_analysis_async(task_id):

#instance of analysisTask
task = AnalysisTask.objects.get(id=task_id)
task.status = "RUNNING" #update status
task.save() #save instance task

try:
#call ai api rather than dummy
results = run_dummy(task.input_code, task.language)

task.results = results #store results
task.status = "COMPLETED" #update status
except Exception(BaseException) as e:
task.status = "FAILED"

task.save()
60 changes: 60 additions & 0 deletions api/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from rest_framework.test import APITestCase
from django.contrib.auth.models import User
from rest_framework import status
from .models import *
from uuid import uuid4


class InitialAnalysisTests(APITestCase):

def setUp(self):
#create user
self.User = User.objects.create_user(
username="username",
password="password"
)
self.client.login(username="username", password="password")

def test_create_analysisTask(self):

response = self.client.post("/api/analysis/",{
"code" : "print('Hello World')", #code to analyze
"language" : "Python" #language of code
}, format="json")

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIn("task_id", response.data) #task_id in data
self.assertEqual(response.data["status"], "QUEUED")

class InitialWorkflowTest(APITestCase):

def setUp(self):
#create user
self.User = User.objects.create_user(
username="username",
password="password"
)
self.client.login(username="username", password="password")

def test_initial_workflow(self):
response = self.client.post("/api/analysis/",{
"code" : "print('Hello Again')", #code to analyze
"language" : "Python" #language of code
}, format="json")

self.assertEqual(response.status_code, status.HTTP_200_OK)

task_id = response.data["task_id"]

task = AnalysisTask.objects.get(id=task_id)

#confirm that dummy ran
self.assertEqual(task.status, "COMPLETED")

result_response = self.client.get(f"/api/analysis/{task_id}/")

#ensure task endpoint
self.assertEqual(result_response.status_code, 200)



8 changes: 8 additions & 0 deletions api/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.contrib.auth import get_user
from django.urls import path
from .views import *

urlpatterns = [
path("analysis/", AnalysisView.as_view(), name="analysis"),
path("analysis/<uuid:task_id>/", StatusView.as_view(), name="analysis-status"),
]
41 changes: 41 additions & 0 deletions api/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#all id related lines are noted and can be deleted or changed if user id is skipped or substituted
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated #for user id
from api.models import AnalysisTask
from api.serializers import AnalysisRequestSerializer
from .tasks import run_analysis_async

class AnalysisView(APIView):
permission_classes = [IsAuthenticated]

#analysis task endpoint
def post(self, request):
serializer = AnalysisRequestSerializer(data=request.data)
serializer.is_valid(raise_exception=True) #deserialize, check correct input and format, raises 400 Bad Request on fail

task = AnalysisTask.objects.create(
user=request.user, #user
input_code=serializer.validated_data["code"],
language=serializer.validated_data["language"],
status="QUEUED"
)

run_analysis_async(str(task.id))

return Response({
"task_id": str(task.id),
"status": task.status
})

class StatusView(APIView):
permission_classes = [IsAuthenticated]
#status endpoint
def get(self, request, task_id):
task = AnalysisTask.objects.get(id=task_id, user=request.user) #user

return Response({
"status": task.status,
"summary": task.results if task.status == "COMPLETED" else None
})

Empty file added config/__init__.py
Empty file.
16 changes: 16 additions & 0 deletions config/asgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
ASGI config for config project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.0/howto/deployment/asgi/
"""

import os

from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')

application = get_asgi_application()
140 changes: 140 additions & 0 deletions config/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
"""
Django settings for config project.

Generated by 'django-admin startproject' using Django 5.0.3.

For more information on this file, see
https://docs.djangoproject.com/en/5.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.0/ref/settings/
"""
import os
from pathlib import Path

#dotenv setup otherwise import and use db.py
from dotenv import load_dotenv
load_dotenv()


# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-y+j3zht6sr%!!2fg0&-ek^21&)yc+y+5a*-ly+@16$8$px)a$@'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'api',
'rest_framework'
]

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'config.urls'

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

WSGI_APPLICATION = 'config.wsgi.application'


# Database
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases



#modified 2/22 to implement PostgreSQL
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.getenv('DB_NAME'),
'USER': os.getenv('DB_USER'),
'PASSWORD': os.getenv('DB_PASS'),
'HOST': os.getenv('DB_HOST'),
'PORT': os.getenv('DB_PORT'),
'OPTIONS': {
'sslmode': 'require',
}
}
}


# Password validation
# https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]


# Internationalization
# https://docs.djangoproject.com/en/5.0/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.0/howto/static-files/

STATIC_URL = 'static/'

# Default primary key field type
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
Loading