Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.31.1 #11

Merged
merged 21 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
bb243b3
removed version line from docker compose yaml (#800)
volumedata21 Aug 28, 2024
0282220
Bump django from 5.0.3 to 5.0.8 (#795)
dependabot[bot] Aug 28, 2024
d898c1b
Bump certifi from 2023.11.17 to 2024.7.4 (#775)
dependabot[bot] Aug 28, 2024
af16a9e
Bump djangorestframework from 3.14.0 to 3.15.2 (#769)
dependabot[bot] Aug 28, 2024
b0610db
Bump urllib3 from 2.1.0 to 2.2.2 (#762)
dependabot[bot] Aug 28, 2024
d9362c9
Add resource linkding logo (#788)
QYG2297248353 Aug 28, 2024
b72697b
Allow use of standard docker `TZ` env var (#765)
watsonbox Aug 28, 2024
36a8427
Add OCI source annotation to link back to source repo (#701)
Ramblurr Aug 28, 2024
749bc1e
Generate fallback URLs for web archive links (#804)
sissbruecker Aug 29, 2024
7d4e659
Run tests in parallel
sissbruecker Aug 29, 2024
0fe6304
Fix overflow in settings page (#805)
sissbruecker Aug 29, 2024
1122d18
Show web archive fallback link in details modal
sissbruecker Aug 29, 2024
190b5ae
Bump version
sissbruecker Aug 30, 2024
36749c3
Update CHANGELOG.md
sissbruecker Aug 30, 2024
5eadb3e
Allow configuring landing page for unauthenticated users (#808)
sissbruecker Aug 31, 2024
79bf4b3
remove unused context processor
sissbruecker Aug 31, 2024
aad62f6
Allow configuring guest user profile (#809)
sissbruecker Aug 31, 2024
20fe88d
Return bookmark tags in RSS feeds (#810)
sissbruecker Aug 31, 2024
1c6e590
Additional filter parameters for RSS feeds (#811)
sissbruecker Aug 31, 2024
b304863
Allow pre-filling notes in new bookmark form (#812)
sissbruecker Aug 31, 2024
90dd61a
Merge branch 'environ' into master
krzysztofjeziorny Sep 2, 2024
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
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
# Changelog

## v1.31.1 (30/08/2024)

### What's Changed
* Include favicons and thumbnails in REST API by @sissbruecker in https://github.com/sissbruecker/linkding/pull/763
* Add Pinkt to the Community section by @fibelatti in https://github.com/sissbruecker/linkding/pull/772
* removed version line from docker compose yaml by @volumedata21 in https://github.com/sissbruecker/linkding/pull/800
* Add resource linkding logo by @QYG2297248353 in https://github.com/sissbruecker/linkding/pull/788
* Allow use of standard docker `TZ` env var by @watsonbox in https://github.com/sissbruecker/linkding/pull/765
* Add OCI source annotation to link back to source repo by @Ramblurr in https://github.com/sissbruecker/linkding/pull/701
* Generate fallback URLs for web archive links by @sissbruecker in https://github.com/sissbruecker/linkding/pull/804
* Fix overflow in settings page by @sissbruecker in https://github.com/sissbruecker/linkding/pull/805
* Bump django from 5.0.3 to 5.0.8 by @dependabot in https://github.com/sissbruecker/linkding/pull/795
* Bump certifi from 2023.11.17 to 2024.7.4 by @dependabot in https://github.com/sissbruecker/linkding/pull/775
* Bump djangorestframework from 3.14.0 to 3.15.2 by @dependabot in https://github.com/sissbruecker/linkding/pull/769
* Bump urllib3 from 2.1.0 to 2.2.2 by @dependabot in https://github.com/sissbruecker/linkding/pull/762

### New Contributors
* @fibelatti made their first contribution in https://github.com/sissbruecker/linkding/pull/772
* @volumedata21 made their first contribution in https://github.com/sissbruecker/linkding/pull/800
* @QYG2297248353 made their first contribution in https://github.com/sissbruecker/linkding/pull/788
* @watsonbox made their first contribution in https://github.com/sissbruecker/linkding/pull/765
* @Ramblurr made their first contribution in https://github.com/sissbruecker/linkding/pull/701

**Full Changelog**: https://github.com/sissbruecker/linkding/compare/v1.31.0...v1.31.1

---

## v1.31.0 (16/06/2024)

### What's Changed
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ tasks:
python manage.py process_tasks

test:
pytest
pytest -n auto

format:
black bookmarks
Expand Down
Binary file added assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 0 additions & 14 deletions bookmarks/context_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,5 @@ def toasts(request):
}


def public_shares(request):
# Only check for public shares for anonymous users
if not request.user.is_authenticated:
query_set = queries.query_shared_bookmarks(
None, request.user_profile, BookmarkSearch(), True
)
has_public_shares = query_set.count() > 0
return {
"has_public_shares": has_public_shares,
}

return {}


def app_version(request):
return {"app_version": utils.app_version}
68 changes: 40 additions & 28 deletions bookmarks/feeds.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from dataclasses import dataclass

from django.contrib.syndication.views import Feed
from django.db.models import QuerySet
from django.db.models import QuerySet, prefetch_related_objects
from django.http import HttpRequest
from django.urls import reverse

from bookmarks import queries
Expand All @@ -11,6 +12,7 @@

@dataclass
class FeedContext:
request: HttpRequest
feed_token: FeedToken | None
query_set: QuerySet[Bookmark]

Expand All @@ -26,13 +28,27 @@ def sanitize(text: str):


class BaseBookmarksFeed(Feed):
def get_object(self, request, feed_key: str):
feed_token = FeedToken.objects.get(key__exact=feed_key)
search = BookmarkSearch(q=request.GET.get("q", ""))
query_set = queries.query_bookmarks(
feed_token.user, feed_token.user.profile, search
def get_object(self, request, feed_key: str | None):
feed_token = FeedToken.objects.get(key__exact=feed_key) if feed_key else None
search = BookmarkSearch(
q=request.GET.get("q", ""),
unread=request.GET.get("unread", ""),
shared=request.GET.get("shared", ""),
)
return FeedContext(feed_token, query_set)
query_set = self.get_query_set(feed_token, search)
return FeedContext(request, feed_token, query_set)

def get_query_set(self, feed_token: FeedToken, search: BookmarkSearch):
raise NotImplementedError

def items(self, context: FeedContext):
limit = context.request.GET.get("limit", 100)
if limit:
data = context.query_set[: int(limit)]
else:
data = list(context.query_set)
prefetch_related_objects(data, "tags")
return data

def item_title(self, item: Bookmark):
return sanitize(item.resolved_title)
Expand All @@ -46,60 +62,56 @@ def item_link(self, item: Bookmark):
def item_pubdate(self, item: Bookmark):
return item.date_added

def item_categories(self, item: Bookmark):
return item.tag_names


class AllBookmarksFeed(BaseBookmarksFeed):
title = "All bookmarks"
description = "All bookmarks"

def get_query_set(self, feed_token: FeedToken, search: BookmarkSearch):
return queries.query_bookmarks(feed_token.user, feed_token.user.profile, search)

def link(self, context: FeedContext):
return reverse("bookmarks:feeds.all", args=[context.feed_token.key])

def items(self, context: FeedContext):
return context.query_set


class UnreadBookmarksFeed(BaseBookmarksFeed):
title = "Unread bookmarks"
description = "All unread bookmarks"

def get_query_set(self, feed_token: FeedToken, search: BookmarkSearch):
return queries.query_bookmarks(
feed_token.user, feed_token.user.profile, search
).filter(unread=True)

def link(self, context: FeedContext):
return reverse("bookmarks:feeds.unread", args=[context.feed_token.key])

def items(self, context: FeedContext):
return context.query_set.filter(unread=True)


class SharedBookmarksFeed(BaseBookmarksFeed):
title = "Shared bookmarks"
description = "All shared bookmarks"

def get_object(self, request, feed_key: str):
feed_token = FeedToken.objects.get(key__exact=feed_key)
search = BookmarkSearch(q=request.GET.get("q", ""))
query_set = queries.query_shared_bookmarks(
def get_query_set(self, feed_token: FeedToken, search: BookmarkSearch):
return queries.query_shared_bookmarks(
None, feed_token.user.profile, search, False
)
return FeedContext(feed_token, query_set)

def link(self, context: FeedContext):
return reverse("bookmarks:feeds.shared", args=[context.feed_token.key])

def items(self, context: FeedContext):
return context.query_set


class PublicSharedBookmarksFeed(BaseBookmarksFeed):
title = "Public shared bookmarks"
description = "All public shared bookmarks"

def get_object(self, request):
search = BookmarkSearch(q=request.GET.get("q", ""))
default_profile = UserProfile()
query_set = queries.query_shared_bookmarks(None, default_profile, search, True)
return FeedContext(None, query_set)
return super().get_object(request, None)

def get_query_set(self, feed_token: FeedToken, search: BookmarkSearch):
return queries.query_shared_bookmarks(None, UserProfile(), search, True)

def link(self, context: FeedContext):
return reverse("bookmarks:feeds.public_shared")

def items(self, context: FeedContext):
return context.query_set
18 changes: 15 additions & 3 deletions bookmarks/middlewares.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
from django.conf import settings
from django.contrib.auth.middleware import RemoteUserMiddleware

from bookmarks.models import UserProfile
from bookmarks.models import UserProfile, GlobalSettings


class CustomRemoteUserMiddleware(RemoteUserMiddleware):
header = settings.LD_AUTH_PROXY_USERNAME_HEADER


standard_profile = UserProfile()
standard_profile.enable_favicons = True


class UserProfileMiddleware:
def __init__(self, get_response):
self.get_response = get_response
Expand All @@ -16,8 +20,16 @@ def __call__(self, request):
if request.user.is_authenticated:
request.user_profile = request.user.profile
else:
request.user_profile = UserProfile()
request.user_profile.enable_favicons = True
# check if a custom profile for guests exists, otherwise use standard profile
guest_profile = None
try:
global_settings = GlobalSettings.get()
if global_settings.guest_profile_user:
guest_profile = global_settings.guest_profile_user.profile
except:
pass

request.user_profile = guest_profile or standard_profile

response = self.get_response(request)

Expand Down
38 changes: 38 additions & 0 deletions bookmarks/migrations/0037_globalsettings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Generated by Django 5.0.8 on 2024-08-31 12:39

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("bookmarks", "0036_userprofile_auto_tagging_rules"),
]

operations = [
migrations.CreateModel(
name="GlobalSettings",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"landing_page",
models.CharField(
choices=[
("login", "Login"),
("shared_bookmarks", "Shared Bookmarks"),
],
default="login",
max_length=50,
),
),
],
),
]
26 changes: 26 additions & 0 deletions bookmarks/migrations/0038_globalsettings_guest_profile_user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 5.0.8 on 2024-08-31 17:54

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("bookmarks", "0037_globalsettings"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.AddField(
model_name="globalsettings",
name="guest_profile_user",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to=settings.AUTH_USER_MODEL,
),
),
]
46 changes: 45 additions & 1 deletion bookmarks/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@ class Meta:

@property
def has_notes(self):
return self.instance and self.instance.notes
return self.initial.get("notes", None) or (
self.instance and self.instance.notes
)


class BookmarkSearch:
Expand Down Expand Up @@ -492,3 +494,45 @@ def generate_key(cls):

def __str__(self):
return self.key


class GlobalSettings(models.Model):
LANDING_PAGE_LOGIN = "login"
LANDING_PAGE_SHARED_BOOKMARKS = "shared_bookmarks"
LANDING_PAGE_CHOICES = [
(LANDING_PAGE_LOGIN, "Login"),
(LANDING_PAGE_SHARED_BOOKMARKS, "Shared Bookmarks"),
]

landing_page = models.CharField(
max_length=50,
choices=LANDING_PAGE_CHOICES,
blank=False,
default=LANDING_PAGE_LOGIN,
)
guest_profile_user = models.ForeignKey(
get_user_model(), on_delete=models.SET_NULL, null=True, blank=True
)

@classmethod
def get(cls):
instance = GlobalSettings.objects.first()
if not instance:
instance = GlobalSettings()
instance.save()
return instance

def save(self, *args, **kwargs):
if not self.pk and GlobalSettings.objects.exists():
raise Exception("There is already one instance of GlobalSettings")
return super(GlobalSettings, self).save(*args, **kwargs)


class GlobalSettingsForm(forms.ModelForm):
class Meta:
model = GlobalSettings
fields = ["landing_page", "guest_profile_user"]

def __init__(self, *args, **kwargs):
super(GlobalSettingsForm, self).__init__(*args, **kwargs)
self.fields["guest_profile_user"].empty_label = "Standard profile"
2 changes: 0 additions & 2 deletions bookmarks/services/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,6 @@ def import_netscape_html(
for batch in batches:
_import_batch(batch, user, options, tag_cache, result)

# Create snapshots for newly imported bookmarks
tasks.schedule_bookmarks_without_snapshots(user)
# Load favicons for newly imported bookmarks
tasks.schedule_bookmarks_without_favicons(user)
# Load previews for newly imported bookmarks
Expand Down
Loading
Loading