diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..e2001dd --- /dev/null +++ b/.dockerignore @@ -0,0 +1,120 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt +pip-selfcheck.json + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +coverage.xml +*.cover + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Sphinx +docs/_build +docs/bin +docs/build +docs/include +docs/Lib +doc/pyvenv.cfg +pyvenv.cfg + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv and pip +.python-version +pyvenv.cfg +bin/ + +# Environments +.venv +env/ +venv/ +ENV/ + + +# mypy +.mypy_cache/ + + +# Database +*.sqlite3* + +# Staticfiles +staticfiles/ + +# virtualenv +bin +include +lib64 +share +Pipfile + +# editors +.vscode +# PyCharm +.idea/ + +# pytest +.pytest_cache + + +# Various junk and temp files +.DS_Store +*~ +.*.sw[po] +.build +.ve +*.bak +/.cache/ +/tmp/ + +# pyenv +/.python-version +/man/ +/.pytest_cache/ +lib64 +tcl + +# Ignore Jupyter Notebook related temp files +.ipynb_checkpoints/ diff --git a/fedcode/forms.py b/fedcode/forms.py index 908c882..98550b9 100644 --- a/fedcode/forms.py +++ b/fedcode/forms.py @@ -20,15 +20,14 @@ class CreateGitRepoForm(forms.ModelForm): class Meta: model = Repository fields = ["url"] - help_texts = { - "url": None, - } def __init__(self, *args, **kwargs): super(CreateGitRepoForm, self).__init__(*args, **kwargs) self.fields["url"].widget.attrs.update( - {"class": "input mb-5", "placeholder": "https://github.com/nexB/vulnerablecode-data"} + {"class": "input", "placeholder": "https://github.com/nexB/vulnerablecode-data"} ) + self.fields["url"].help_text = "" + self.fields["url"].label = "" class CreateNoteForm(forms.ModelForm): @@ -39,9 +38,10 @@ class Meta: def __init__(self, *args, **kwargs): super(CreateNoteForm, self).__init__(*args, **kwargs) self.fields["content"].widget.attrs.update( - {"class": "textarea", "placeholder": "Add a note...", "rows": 5} + {"class": "textarea", "placeholder": "Comment...", "rows": 5} ) self.fields["content"].label = "" + self.fields["content"].help_text = "" class ReviewStatusForm(forms.ModelForm): @@ -109,9 +109,8 @@ class SearchPackageForm(forms.Form): label=False, widget=forms.TextInput( attrs={ - "placeholder": "Please enter a valid purl ex: pkg:maven/org.apache.commons/io", - "class": "input is-rounded", - "style": "width: 90%;", + "placeholder": "Search a package...", + "class": "input ", }, ), ) @@ -137,9 +136,8 @@ class SearchRepositoryForm(forms.Form): label=False, widget=forms.TextInput( attrs={ - "placeholder": "Please Enter a Repository URL ex: https://github.com/nexB/vulnerablecode-data", - "class": "input is-rounded", - "style": "width: 90%;", + "placeholder": "Search a repository...", + "class": "input", }, ), ) diff --git a/fedcode/middleware.py b/fedcode/middleware.py new file mode 100644 index 0000000..f08378d --- /dev/null +++ b/fedcode/middleware.py @@ -0,0 +1,30 @@ +# +# Copyright (c) nexB Inc. and others. All rights reserved. +# FederatedCode is a trademark of nexB Inc. +# SPDX-License-Identifier: Apache-2.0 +# See http://www.apache.org/licenses/LICENSE-2.0 for the license text. +# See https://github.com/nexB/federatedcode for support or download. +# See https://aboutcode.org for more information about AboutCode.org OSS projects. +# + +import zoneinfo + +from django.utils import timezone + + +class TimezoneMiddleware: + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + try: + # Activate local timezone for user using cookies + tzname = request.COOKIES.get("user_timezone") + if tzname: + timezone.activate(zoneinfo.ZoneInfo(tzname)) + else: + timezone.deactivate() + except Exception as e: + timezone.deactivate() + + return self.get_response(request) diff --git a/fedcode/migrations/0005_remove_person_avatar.py b/fedcode/migrations/0005_remove_person_avatar.py new file mode 100644 index 0000000..219af80 --- /dev/null +++ b/fedcode/migrations/0005_remove_person_avatar.py @@ -0,0 +1,17 @@ +# Generated by Django 5.1.2 on 2024-12-27 17:48 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("fedcode", "0004_alter_vulnerability_unique_together"), + ] + + operations = [ + migrations.RemoveField( + model_name="person", + name="avatar", + ), + ] diff --git a/fedcode/models.py b/fedcode/models.py index 2350714..1daf383 100644 --- a/fedcode/models.py +++ b/fedcode/models.py @@ -50,6 +50,10 @@ class RemoteActor(models.Model): help_text="A field to track when remote actor are updated", ) + @property + def safe_url(self): + return f"{self.url.rstrip('/')}/" + class Actor(models.Model): """ @@ -227,6 +231,11 @@ def reputation_value(self): def absolute_url(self): return full_reverse("note-page", self.id) + @property + def acct_avatar(self): + person = Person.objects.get(user__username=self.username) + return person.avatar + @property def to_ap(self): return { @@ -290,6 +299,10 @@ def __str__(self): def followers_count(self): return Follow.objects.filter(package=self).count() + @property + def notes_count(self): + return Note.objects.filter(acct=self.acct).count() + @property def followers(self): return Follow.objects.filter(package=self).values("person_id") @@ -350,16 +363,9 @@ def to_ap(self): class Person(Actor): """ - A person is a user can follow pacakge or just vote or create a notes + A person is a user can follow package or just vote or create a notes """ - avatar = models.ImageField( - upload_to="uploads/", - help_text="", - default="favicon-16x16.png", - null=True, - ) - user = models.OneToOneField( User, null=True, @@ -391,13 +397,24 @@ class Meta: ), ] + @property + def avatar(self): + from hashlib import sha256 + + email = "" + if self.user and (email := self.user.email): + email = email.strip().lower() + + gravatar = sha256(email.encode("utf-8")).hexdigest() + return f"https://gravatar.com/avatar/{gravatar}" + @property def local(self): return bool(self.user) @property def avatar_absolute_url(self): - return f'{"https://"}{FEDERATEDCODE_DOMAIN}{self.avatar.url}' + return self.avatar # TODO raise error if the user doesn't have a user or remote actor @property @@ -425,13 +442,13 @@ def absolute_url_ap(self): @property def inbox_url(self): if not self.local: - return urljoin(self.remote_actor.url, "inbox") + return urljoin(self.remote_actor.safe_url, "inbox") return full_reverse("user-inbox", self.user.username) @property def outbox_url(self): if not self.local: - return urljoin(self.remote_actor.url, "outbox") + return urljoin(self.remote_actor.safe_url, "outbox") return full_reverse("user-outbox", self.user.username) @property @@ -443,7 +460,7 @@ def key_id(self): if self.user: return full_reverse("user-ap-profile", self.user.username) + "#main-key" else: - return self.remote_actor.url + "#main-key" + return self.remote_actor.safe_url + "#main-key" @property def to_ap(self): @@ -604,7 +621,7 @@ class Vulnerability(models.Model): ) class Meta: - unique_together = ('id', 'repo') + unique_together = ("id", "repo") @property def absolute_url(self): diff --git a/fedcode/pipes/utils.py b/fedcode/pipes/utils.py index adc06c2..069fa74 100644 --- a/fedcode/pipes/utils.py +++ b/fedcode/pipes/utils.py @@ -19,6 +19,8 @@ def create_note(pkg, note_dict): + # TODO: also take argument for source of the note ideally github blob for + # for file. note, _ = Note.objects.get_or_create(acct=pkg.acct, content=saneyaml.dump(note_dict)) pkg.notes.add(note) create_activity = CreateActivity(actor=pkg.to_ap, object=note.to_ap) diff --git a/fedcode/templates/403.html b/fedcode/templates/403.html new file mode 100644 index 0000000..ef9c98c --- /dev/null +++ b/fedcode/templates/403.html @@ -0,0 +1,21 @@ +{% extends "base.html" %} + +{% block title %} +Permission Denied +{% endblock %} + +{% block content %} + +{% endblock %} diff --git a/fedcode/templates/404.html b/fedcode/templates/404.html new file mode 100644 index 0000000..1cebca3 --- /dev/null +++ b/fedcode/templates/404.html @@ -0,0 +1,21 @@ +{% extends "base.html" %} + +{% block title %} +Page Not Found +{% endblock %} + +{% block content %} + +{% endblock %} \ No newline at end of file diff --git a/fedcode/templates/base.html b/fedcode/templates/base.html index 6f744ab..c41c523 100644 --- a/fedcode/templates/base.html +++ b/fedcode/templates/base.html @@ -6,26 +6,37 @@ {% block title %}FederatedCode.io{% endblock %} - + - + - {% block json_ld_script %} - {% endblock %} - + {% block json_ld_script %}{% endblock %} {% block extra-head %}{% endblock %} - - {% include "navbar.html" %} - {% include "messages.html" %} - {% block content %} + +
+ {% include "navbar.html" %} + {% include "messages.html" %} + {% block content %} + {% endblock %} + {% include "footer.html" %} +
+ + + + {% block scripts %} {% endblock %} - {% include "footer.html" %} \ No newline at end of file diff --git a/fedcode/templates/create_repository.html b/fedcode/templates/create_repository.html index 501fc8f..bc78b91 100644 --- a/fedcode/templates/create_repository.html +++ b/fedcode/templates/create_repository.html @@ -1,31 +1,36 @@ {% extends "base.html" %} + {% block title %} -Sign up page +Add Repository {% endblock %} {% block content %}
- {% if form.errors %} -
-
-

Error

-
-
+ {% if form.errors %} +
+
+

Error

+
+
{{ form.errors }} -
-
-{% endif %} -

Create Git Repository

-
- {% csrf_token %} +
+
+ {% endif %} +

Add Git Repository

+ + {% csrf_token %} +
+
{{ form.as_p }} - - +
+
+ +
+
+
-
- {% endblock %} \ No newline at end of file diff --git a/fedcode/templates/footer.html b/fedcode/templates/footer.html index 949c6ec..0290f37 100644 --- a/fedcode/templates/footer.html +++ b/fedcode/templates/footer.html @@ -1,9 +1,12 @@ -