diff --git a/conservancy/content/copyleft-compliance/vizio.html b/conservancy/content/copyleft-compliance/vizio.html index 26e1004a25a9eaf53d589f3239be6202374bfaa3..cfb9aff2a9c90a6f93a1143a9b32a8c95178144a 100644 --- a/conservancy/content/copyleft-compliance/vizio.html +++ b/conservancy/content/copyleft-compliance/vizio.html @@ -49,10 +49,20 @@ Original Complaint (2021-10-19)
  • Judge's ruling denying Vizio's Motion for Summary Judgment
  • +
  • SFC's +First Amended Complaint (2024-01-10)
  • SFC's Motion for Summary Adjudication
  • + Motion for Summary Adjudication +
  • Vizio's + response to SFC's Motion for Summary Adjudication
  • +
  • SFC's + reply to Vizio's response to SFC's Motion for Summary Adjudication
  • +
  • Judge's + ruling partially granting SFC's Motion for Summary Adjudication
  • +

    MEDIA CONTACT

    diff --git a/conservancy/settings/base.py b/conservancy/settings/base.py index 22ebd15079b4c7b4d15995b409084de210acc215..0ed97181283e062de13cc4f510c59285eafa77bf 100644 --- a/conservancy/settings/base.py +++ b/conservancy/settings/base.py @@ -123,12 +123,20 @@ TIME_ZONE = 'America/New_York' LANGUAGE_CODE = 'en-us' USE_TZ = False +STORAGES = { + 'default': { + 'BACKEND': 'django.core.files.storage.FileSystemStorage', + }, + 'staticfiles': { + 'BACKEND': 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage', + }, +} + STATIC_URL = '/static/' STATIC_ROOT = BASE_DIR.parent / 'collected_static' STATICFILES_DIRS = [ BASE_DIR / 'static', ] -STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage' MEDIA_ROOT = BASE_DIR.parent / 'media' MEDIA_URL = '/media/' diff --git a/conservancy/static/css/conservancy.css b/conservancy/static/css/conservancy.css index fff8b58342a96c5ad23b138e21200470dc09c6e7..ed671721ee715b7fb4dd9c271b24a27fba10e519 100644 --- a/conservancy/static/css/conservancy.css +++ b/conservancy/static/css/conservancy.css @@ -76,12 +76,6 @@ form[action$="#fixme"]:before { text-align: center; } -input:focus { - z-index: 3; - border-color: #86b7fe; - box-shadow: 0 0 0 .25rem rgb(236, 99, 67, .5); -} - video { max-width: 100%; } diff --git a/conservancy/usethesource/admin.py b/conservancy/usethesource/admin.py index 6a886813114ca4e199b0b536f3e4dc1d063e6f68..9081928f0abee68684ee9f69b0481ef5323a11d5 100644 --- a/conservancy/usethesource/admin.py +++ b/conservancy/usethesource/admin.py @@ -1,7 +1,7 @@ from django.contrib import admin from .emails import make_candidate_email -from .models import Candidate, Comment +from .models import Candidate, Comment, SourceOffer class CommentInline(admin.TabularInline): @@ -36,3 +36,10 @@ class CandidateAdmin(admin.ModelAdmin): # Announce the new candidate email = make_candidate_email(obj, request.user) email.send() + + +@admin.register(SourceOffer) +class SourceOfferAdmin(admin.ModelAdmin): + list_display = ['time', 'vendor', 'device'] + fields = ['time', 'vendor', 'device', 'photo'] + readonly_fields = ['time'] diff --git a/conservancy/usethesource/forms.py b/conservancy/usethesource/forms.py index 497c66f440157847382f16da2389af7e3c530a17..e7618c6de57ddf9cc41bfb2989f9b75b47e2c089 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 0000000000000000000000000000000000000000..5eb1094d4c29625e13b2d63036f9fdcee027bc5e --- /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/migrations/0010_sourceoffer_time.py b/conservancy/usethesource/migrations/0010_sourceoffer_time.py new file mode 100644 index 0000000000000000000000000000000000000000..0f63063febac80f113839d336a3f0e9a515758a4 --- /dev/null +++ b/conservancy/usethesource/migrations/0010_sourceoffer_time.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.11 on 2024-07-29 09:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('usethesource', '0009_sourceoffer'), + ] + + operations = [ + migrations.AddField( + model_name='sourceoffer', + name='time', + field=models.DateTimeField(auto_now_add=True, null=True), + ), + ] diff --git a/conservancy/usethesource/models.py b/conservancy/usethesource/models.py index 6b070e5443674e96c11d27e581ac69f51a4affc3..5ad68be361914fc094a18908664b3d08157ebc3e 100644 --- a/conservancy/usethesource/models.py +++ b/conservancy/usethesource/models.py @@ -67,3 +67,13 @@ class Comment(models.Model): class Meta: ordering = ['id'] + + +class SourceOffer(models.Model): + time = models.DateTimeField(auto_now_add=True, null=True) + vendor = models.CharField('Vendor name', max_length=50) + device = models.CharField('Device name', max_length=50) + photo = models.ImageField(upload_to='usethesource/offers') + + def __str__(self): + return f'{self.vendor} {self.device}' diff --git a/conservancy/usethesource/templates/usethesource/landing_page.html b/conservancy/usethesource/templates/usethesource/landing_page.html index 5274674cf8c8e8a3148a8ac5069b04f9767a7b37..496da5e169ee2b457110cba20f9aafe78c571878 100644 --- a/conservancy/usethesource/templates/usethesource/landing_page.html +++ b/conservancy/usethesource/templates/usethesource/landing_page.html @@ -24,7 +24,7 @@

    One crucial way to get involved is to let us know about any source candidates you find! Many devices have an offer for source code (check the manual or device's user interface to find it) and we'd be very interested to know what they send you when you request it. Here are the steps to submit a new source candidate to list on this page:

      -
    1. find a source candidate offered by a company - normally this is offered to you in the manual or user interface of your device, through a link or email address (the company's GitHub page is not canonical, unless they explicitly say so in this offer)
    2. +
    3. find a source candidate offered by a company - normally this is offered to you in the manual or user interface of your device, through a link or email address (the company's GitHub page is not canonical, unless they explicitly say so in this offer). If you're curious what an offer is, check out the PDFs referenced in our submission to the FTC, and submit a picture/image of a new offer so we can test it for you if you like
    4. upload the source candidate to us - write down the file name(s) you uploaded for the next step (can be multiple), and upload a firmware image if you have it and are ok with us publishing it
    5. diff --git a/conservancy/usethesource/templates/usethesource/upload_offer.html b/conservancy/usethesource/templates/usethesource/upload_offer.html new file mode 100644 index 0000000000000000000000000000000000000000..6c93a6a70a7d6c60aef37692b4f03272a07e8238 --- /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/templates/usethesource/upload_success_partial.html b/conservancy/usethesource/templates/usethesource/upload_success_partial.html new file mode 100644 index 0000000000000000000000000000000000000000..e945a161186ff8a7f0c1a65c11cc85b9323dc4e5 --- /dev/null +++ b/conservancy/usethesource/templates/usethesource/upload_success_partial.html @@ -0,0 +1 @@ +

      Thanks! We've received your offer for source.

      diff --git a/conservancy/usethesource/urls.py b/conservancy/usethesource/urls.py index ba7e3833beec36534905c606ba40773c5a383b56..0b30afd925bcc6c1d5dabb8a14e67e52551b49d9 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 6d6446ede701dc1e9203f947a340b95175eb853a..f31e5939ac48842e5824d32bb57ea59dd8d4a593 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}) diff --git a/requirements.txt b/requirements.txt index 6fca663386022087ad176655c4fcf116c2596dbc..b2d2bb7c800969172695dd7868a4d4ae5bc8d576 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # Installed in virtualenv -Django==4.2.11 +Django==4.2.16 # Provided by Debian Bookworm. beautifulsoup4==4.11.2 html5lib==1.1