diff --git a/mysite/settings/base.py b/mysite/settings/base.py index 3c19169..37d6808 100644 --- a/mysite/settings/base.py +++ b/mysite/settings/base.py @@ -38,6 +38,7 @@ 'django_celery_beat', 'django_filters', 'punchlist', + 'submission', 'mysite.templatetags.custom_filters', 'import_export', 'storages', diff --git a/mysite/urls.py b/mysite/urls.py index 2967be5..83ee810 100644 --- a/mysite/urls.py +++ b/mysite/urls.py @@ -33,6 +33,9 @@ path("logout", views.logout_request, name= "logout"), path("edit_profile/", views.edit_profile, name="edit_profile"), + # qr code submissions + path('submission/', include('submission.urls')), + # password reset path('password_reset/', auth_views.PasswordResetView.as_view(), name='password_reset'), path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'), diff --git a/punchlist/__init__.py b/punchlist/__init__.py index f3c5e8d..8b37ec7 100644 --- a/punchlist/__init__.py +++ b/punchlist/__init__.py @@ -1,5 +1,2 @@ # This will make sure the app is always imported when -# Django starts so that shared_task will use this app. -from celery import app as celery_app -__all__ = ('celery_app',) diff --git a/punchlist/labs.py b/punchlist/labs.py index a01fd8f..ae9fb66 100644 --- a/punchlist/labs.py +++ b/punchlist/labs.py @@ -12,8 +12,6 @@ def get_products(): url = "https://insights-api.buildly.io/product/product/" headers = { "Authorization ": f"Token {os.environ.get('INSIGHTS_API_KEY')}" } - # headers = { "Authorization ": "Token qiqMN09rftSmuTEhiuviA1tdHWlCe2" } - # headers = { "Authorization ": "Token 6y2lTVWR8EXMRwTAg6lnzOLhPrmHBo"} print(url) print(headers) response = requests.get(url, headers=headers) @@ -30,7 +28,6 @@ def get_products(): def get_releases(product_id): url = f"https://insights-api.buildly.io/release/release/?product_uuid={product_id}" headers = { "Authorization ": f"Token {os.environ.get('INSIGHTS_API_KEY')}" } - # headers = {"Authorization : Token qiqMN09rftSmuTEhiuviA1tdHWlCe2"} response = requests.get(url, headers=headers) if response.status_code == 200: diff --git a/punchlist/templates/agency_showcase.html b/punchlist/templates/agency_showcase.html index 2c1d0f0..db57952 100644 --- a/punchlist/templates/agency_showcase.html +++ b/punchlist/templates/agency_showcase.html @@ -60,7 +60,7 @@

Based on Skills Matching

{{ agency.agency_name }} {% if agency.certified %} - + {% endif %}

diff --git a/requirements.txt b/requirements.txt index 46ef85a..2ced3f6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,4 +25,5 @@ drf-yasg==1.21.7 sendgrid django-cors-headers django-allauth -django-import-export \ No newline at end of file +django-import-export +qrcode \ No newline at end of file diff --git a/submission/.DS_Store b/submission/.DS_Store new file mode 100644 index 0000000..c1b88fe Binary files /dev/null and b/submission/.DS_Store differ diff --git a/submission/__init__.py b/submission/__init__.py new file mode 100644 index 0000000..69cabcc --- /dev/null +++ b/submission/__init__.py @@ -0,0 +1 @@ +# This will make sure the app is always imported when diff --git a/submission/admin.py b/submission/admin.py new file mode 100644 index 0000000..1f93cba --- /dev/null +++ b/submission/admin.py @@ -0,0 +1,8 @@ +from .models import * +from django.contrib import admin + +from import_export.admin import ImportExportModelAdmin +from import_export import resources + +admin.site.register(Submission, SubmissionAdmin) +admin.site.register(SubmissionLink, SubmissionLinkAdmin) diff --git a/submission/forms.py b/submission/forms.py new file mode 100644 index 0000000..f59d3d6 --- /dev/null +++ b/submission/forms.py @@ -0,0 +1,9 @@ +# submission/forms.py + +from django import forms +from .models import Submission + +class SubmissionForm(forms.ModelForm): + class Meta: + model = Submission + fields = ['name', 'email', 'description'] diff --git a/submission/migrations/0001_initial.py b/submission/migrations/0001_initial.py new file mode 100644 index 0000000..67edf32 --- /dev/null +++ b/submission/migrations/0001_initial.py @@ -0,0 +1,40 @@ +# Generated by Django 3.2.25 on 2024-08-22 17:33 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='SubmissionLink', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('unique_url', models.URLField(max_length=255, unique=True)), + ('qr_code', models.ImageField(blank=True, upload_to='qr_codes/')), + ('create_date', models.DateTimeField(blank=True, null=True)), + ('edit_date', models.DateTimeField(blank=True, null=True)), + ('admin_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Submission', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ('email', models.EmailField(max_length=254)), + ('description', models.TextField()), + ('create_date', models.DateTimeField(blank=True, null=True)), + ('edit_date', models.DateTimeField(blank=True, null=True)), + ('submission_link', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='submission.submissionlink')), + ], + ), + ] diff --git a/submission/migrations/__init__.py b/submission/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/submission/models.py b/submission/models.py new file mode 100644 index 0000000..a09423a --- /dev/null +++ b/submission/models.py @@ -0,0 +1,52 @@ +from datetime import timedelta +from decimal import Decimal +import uuid +import datetime + +from django.db import models +from django.contrib.auth.models import User +from django.utils.crypto import get_random_string +from django.contrib import admin +from django.utils import timezone + +class SubmissionLink(models.Model): + admin_user = models.ForeignKey(User, on_delete=models.CASCADE) + unique_url = models.URLField(max_length=255, unique=True) + qr_code = models.ImageField(upload_to='qr_codes/', blank=True) + create_date = models.DateTimeField(null=True, blank=True) + edit_date = models.DateTimeField(null=True, blank=True) + + + def save(self, *args, **kwargs): + # onsave add create date or update edit date + if self.create_date == None: + self.create_date = timezone.now() + self.edit_date = timezone.now() + if not self.unique_url: + self.unique_url = get_random_string(32) # Generates a random URL string + super().save(*args, **kwargs) + + +class SubmissionLinkAdmin(admin.ModelAdmin): + list_display = ('admin_user','unique_url','create_date','edit_date') + display = 'Submission Link Admin' + +class Submission(models.Model): + submission_link = models.ForeignKey(SubmissionLink, on_delete=models.CASCADE) + name = models.CharField(max_length=100) + email = models.EmailField() + description = models.TextField() + create_date = models.DateTimeField(null=True, blank=True) + edit_date = models.DateTimeField(null=True, blank=True) + + def save(self, *args, **kwargs): + # onsave add create date or update edit date + if self.create_date == None: + self.create_date = timezone.now() + self.edit_date = timezone.now() + super(Submission, self).save(*args, **kwargs) + + +class SubmissionAdmin(admin.ModelAdmin): + list_display = ('submission_link','name','email','create_date','edit_date') + display = 'Submission Admin' \ No newline at end of file diff --git a/submission/serializer_views.py b/submission/serializer_views.py new file mode 100644 index 0000000..6b26581 --- /dev/null +++ b/submission/serializer_views.py @@ -0,0 +1,14 @@ +from rest_framework import generics +from .models import * +from .serializers import * +from rest_framework.authentication import TokenAuthentication +from rest_framework.permissions import IsAuthenticated + + +class PositionList(generics.ListCreateAPIView): + queryset = Position.objects.all() + serializer_class = PositionSerializer + +class PositionDetail(generics.RetrieveUpdateDestroyAPIView): + queryset = Position.objects.all() + serializer_class = PositionSerializer diff --git a/submission/serializers.py b/submission/serializers.py new file mode 100644 index 0000000..14d1803 --- /dev/null +++ b/submission/serializers.py @@ -0,0 +1,12 @@ +from rest_framework import serializers +from .models import * + +class PositionSerializer(serializers.ModelSerializer): + class Meta: + model = Position + fields = '__all__' + +class BugSerializer(serializers.ModelSerializer): + class Meta: + model = Bug + fields = '__all__' diff --git a/submission/templates/link_generated.html b/submission/templates/link_generated.html new file mode 100644 index 0000000..3a758da --- /dev/null +++ b/submission/templates/link_generated.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} + +{% block content %} +

Your unique submission link and QR code:

+

URL: {{ submission_link.unique_url }}

+QR Code +{% endblock %} \ No newline at end of file diff --git a/submission/templates/submission_form.html b/submission/templates/submission_form.html new file mode 100644 index 0000000..674f7e5 --- /dev/null +++ b/submission/templates/submission_form.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} + +{% block content %} + +

Submit Your Information

+
+ {% csrf_token %} + {{ form.as_p }} + +
+ +{% endblock %} diff --git a/submission/urls.py b/submission/urls.py new file mode 100644 index 0000000..082ade5 --- /dev/null +++ b/submission/urls.py @@ -0,0 +1,7 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path('generate/', views.generate_link, name='generate_link'), + path('submit//', views.submission_form, name='submission_form'), +] diff --git a/submission/views.py b/submission/views.py new file mode 100644 index 0000000..6649602 --- /dev/null +++ b/submission/views.py @@ -0,0 +1,43 @@ +from django.shortcuts import render, redirect, get_object_or_404 +from django.contrib.auth.decorators import login_required +from django.http import HttpResponse +from .models import SubmissionLink, Submission +from .forms import SubmissionForm +import qrcode + +@login_required +def generate_link(request): + submission_link = SubmissionLink.objects.create(admin_user=request.user) + + # Generate QR code + qr = qrcode.QRCode( + version=1, + error_correction=qrcode.constants.ERROR_CORRECT_L, + box_size=10, + border=4, + ) + qr.add_data(submission_link.unique_url) + qr.make(fit=True) + + img = qr.make_image(fill='black', back_color='white') + img_path = f'media/qr_codes/{submission_link.unique_url}.png' + img.save(img_path) + + submission_link.qr_code = img_path + submission_link.save() + + return render(request, 'submission/link_generated.html', {'submission_link': submission_link}) + +def submission_form(request, unique_url): + submission_link = get_object_or_404(SubmissionLink, unique_url=unique_url) + if request.method == 'POST': + form = SubmissionForm(request.POST) + if form.is_valid(): + submission = form.save(commit=False) + submission.submission_link = submission_link + submission.save() + return HttpResponse('Submission successful.') + else: + form = SubmissionForm() + + return render(request, 'submission/submission_form.html', {'form': form})