From 6a2ea41aa6edc4ce02323c24e45b9664b08ad8fa Mon Sep 17 00:00:00 2001 From: Ben Sturmfels Date: Mon, 29 Jul 2024 23:29:25 +1000 Subject: [PATCH] usethesource: Add prototype "upload offer for source" --- conservancy/usethesource/forms.py | 13 ++++- .../migrations/0009_sourceoffer.py | 30 ++++++++++++ conservancy/usethesource/models.py | 6 +++ .../templates/usethesource/upload_offer.html | 49 +++++++++++++++++++ conservancy/usethesource/urls.py | 1 + conservancy/usethesource/views.py | 20 +++++++- 6 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 conservancy/usethesource/migrations/0009_sourceoffer.py create mode 100644 conservancy/usethesource/templates/usethesource/upload_offer.html diff --git a/conservancy/usethesource/forms.py b/conservancy/usethesource/forms.py index 497c66f4..e7618c6d 100644 --- a/conservancy/usethesource/forms.py +++ b/conservancy/usethesource/forms.py @@ -1,6 +1,6 @@ from django import forms -from .models import Comment +from .models import Comment, SourceOffer class CommentForm(forms.ModelForm): @@ -17,3 +17,14 @@ class CommentForm(forms.ModelForm): class DownloadForm(forms.Form): agree = forms.BooleanField(label="I understand that the goal of this process is to determine compliance with FOSS licenses, and that in downloading the source code candidate and/or firmware image, I am assisting SFC as a volunteer to investigate that question. I, therefore, promise and represent that I will not copy, distribute, modify, or otherwise use this source code candidate and/or firmware image for any purpose other than to help SFC evaluate the source code candidate for compliance with the terms of FOSS licenses, including but not limited to any version of the GNU General Public License. Naturally, if I determine in good faith that portions of the source code candidate and/or firmware image are subject to a FOSS license and are compliant with it, I may copy, distribute, modify, or otherwise use those portions in accordance with the FOSS license, and I take full responsibility for that determination and subsequent use.") + + +class SourceOfferForm(forms.ModelForm): + class Meta: + model = SourceOffer + fields = ['vendor', 'device', 'photo'] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields['photo'].widget.attrs['capture'] = 'camera' + self.fields['photo'].widget.attrs['accept'] = 'image/*' diff --git a/conservancy/usethesource/migrations/0009_sourceoffer.py b/conservancy/usethesource/migrations/0009_sourceoffer.py new file mode 100644 index 00000000..5eb1094d --- /dev/null +++ b/conservancy/usethesource/migrations/0009_sourceoffer.py @@ -0,0 +1,30 @@ +# Generated by Django 4.2.11 on 2024-07-22 08:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('usethesource', '0008_comment_attribute_to'), + ] + + operations = [ + migrations.CreateModel( + name='SourceOffer', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name='ID', + ), + ), + ('vendor', models.CharField(max_length=50, verbose_name='Vendor name')), + ('device', models.CharField(max_length=50, verbose_name='Device name')), + ('photo', models.ImageField(upload_to='usethesource/offers')), + ], + ), + ] diff --git a/conservancy/usethesource/models.py b/conservancy/usethesource/models.py index 6b070e54..64e817f5 100644 --- a/conservancy/usethesource/models.py +++ b/conservancy/usethesource/models.py @@ -67,3 +67,9 @@ class Comment(models.Model): class Meta: ordering = ['id'] + + +class SourceOffer(models.Model): + vendor = models.CharField('Vendor name', max_length=50) + device = models.CharField('Device name', max_length=50) + photo = models.ImageField(upload_to='usethesource/offers') diff --git a/conservancy/usethesource/templates/usethesource/upload_offer.html b/conservancy/usethesource/templates/usethesource/upload_offer.html new file mode 100644 index 00000000..6c93a6a7 --- /dev/null +++ b/conservancy/usethesource/templates/usethesource/upload_offer.html @@ -0,0 +1,49 @@ +{% extends "usethesource/base.html" %} + +{% block title %}Upload an offer for source - Software Freedom Conservancy{% endblock %} + +{% block head %} + {{ block.super }} + +{% endblock %} + +{% block content %} + {{ block.super }} + +
+

Upload an offer for source

+
+ +
+ {% csrf_token %} + {{ form.non_field_errors }} +
+ {{ form.vendor.errors }} + + {{ form.vendor }} +
+
+ {{ form.device.errors }} + + {{ form.device }} +
+
+ {{ form.photo.errors }} + + {{ form.photo }} +
+ +
+ +
+
+ + +{% endblock content %} diff --git a/conservancy/usethesource/urls.py b/conservancy/usethesource/urls.py index ba7e3833..0b30afd9 100644 --- a/conservancy/usethesource/urls.py +++ b/conservancy/usethesource/urls.py @@ -13,4 +13,5 @@ urlpatterns = [ path('delete-comment///', views.delete_comment, name='delete_comment'), path('add-button//', views.add_button, name='add_button'), path('ccirt-process/', views.ccirt_process, name='ccirt_process'), + path('offer/', views.upload_offer, name='upload_offer'), ] diff --git a/conservancy/usethesource/views.py b/conservancy/usethesource/views.py index 6d6446ed..f31e5939 100644 --- a/conservancy/usethesource/views.py +++ b/conservancy/usethesource/views.py @@ -3,7 +3,7 @@ from django.core.exceptions import PermissionDenied from django.shortcuts import get_object_or_404, redirect, render from .models import Candidate, Comment -from .forms import CommentForm, DownloadForm +from .forms import CommentForm, DownloadForm, SourceOfferForm from .emails import make_comment_email @@ -91,3 +91,21 @@ def add_button(request, slug): def ccirt_process(request): return render(request, 'usethesource/ccirt_process.html', {}) + + +def handle_uploaded_file(f): + with open("some/file/name.txt", "wb+") as destination: + for chunk in f.chunks(): + destination.write(chunk) + +def upload_offer(request): + if request.method == 'POST': + form = SourceOfferForm(request.POST, request.FILES) + if form.is_valid(): + form.save() + return render(request, 'usethesource/upload_success_partial.html') + else: + return render(request, 'usethesource/upload_offer.html', {'form': form}) + else: + form = SourceOfferForm() + return render(request, 'usethesource/upload_offer.html', {'form': form})