aboutsummaryrefslogtreecommitdiff
path: root/back-end/src
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2024-04-09 17:37:41 -0400
committerLibravatar vnugent <public@vaughnnugent.com>2024-04-09 17:37:41 -0400
commit5877c86b1da4eb4e9e74378709c546933dc63cf4 (patch)
tree5ba2556e42510cbbdf9c287f67041c1b1eb46206 /back-end/src
parent3c15d5471d5134f072365378b04693903419b092 (diff)
Squashed commit of the following:v0.1.3
commit 56e0a38b2ca246e8beeaef3c6c4b9c0ce7d0f09b Author: vnugent <public@vaughnnugent.com> Date: Tue Apr 9 17:35:13 2024 -0400 chore(app): Update deps, login spinner, curl msg, view prep commit 0945210c0492dd8a8de99ccd8e5e66cf05e3a1c1 Merge: 24fac82 3c15d54 Author: vnugent <public@vaughnnugent.com> Date: Tue Apr 2 14:58:59 2024 -0400 Merge branch 'master' into develop commit 24fac82efe9e5c18e86ed535678640e7401472db Author: vnugent <public@vaughnnugent.com> Date: Tue Apr 2 14:54:20 2024 -0400 ci: Configure manual dep versions commit d2ae31ec919d72e66d8b40db8394b55efd6ea6d3 Author: vnugent <public@vaughnnugent.com> Date: Sun Mar 31 22:19:53 2024 -0400 ci: Native compression support for win commit fa7fdef79c6d468022b77f81314ac129fe0cdc32 Merge: 308092d a01220a Author: vnugent <public@vaughnnugent.com> Date: Wed Mar 13 21:26:55 2024 -0400 Merge branch 'master' into develop commit 308092d6d743d0ba8f7ca86fd77e9c837dc46e88 Merge: 48637a8 9134093 Author: vnugent <public@vaughnnugent.com> Date: Wed Mar 13 21:01:02 2024 -0400 Merge branch 'master' into develop commit 48637a8781fc951c307216f604fc1610e68691c3 Merge: 1e08c6d e326736 Author: vnugent <public@vaughnnugent.com> Date: Wed Mar 13 16:20:35 2024 -0400 Merge branch 'master' into develop commit 1e08c6d2112459dc02a0ab873123c4a363b01d21 Author: vnugent <public@vaughnnugent.com> Date: Wed Mar 13 16:17:58 2024 -0400 ci: verified container build ready for next release commit 85a1e5b7cc5c99e97a2d4e99bbceb0d2139742ff Author: vnugent <public@vaughnnugent.com> Date: Tue Mar 12 22:05:16 2024 -0400 ci: exciting bare-metal build process, os support, smaller packages commit 748cdbf4880d830fd794e92856e8c35a46e4f884 Author: vnugent <public@vaughnnugent.com> Date: Mon Mar 11 21:21:18 2024 -0400 feat(app): #1 update libs & add curl support
Diffstat (limited to 'back-end/src')
-rw-r--r--back-end/src/Cache/UserSettings.cs35
-rw-r--r--back-end/src/Cache/UserSettingsStore.cs48
-rw-r--r--back-end/src/Endpoints/BookmarkEndpoint.cs26
-rw-r--r--back-end/src/Model/BookmarkStore.cs38
-rw-r--r--back-end/src/Model/SimpleBookmarkContext.cs54
-rw-r--r--back-end/src/Model/UserSettingsDbStore.cs75
-rw-r--r--back-end/src/Model/UserSettingsEntry.cs39
-rw-r--r--back-end/src/SimpleBookmark.csproj8
8 files changed, 73 insertions, 250 deletions
diff --git a/back-end/src/Cache/UserSettings.cs b/back-end/src/Cache/UserSettings.cs
deleted file mode 100644
index b656f83..0000000
--- a/back-end/src/Cache/UserSettings.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-
-using System.Text.Json.Serialization;
-
-using MemoryPack;
-
-namespace SimpleBookmark.Cache
-{
- [MemoryPackable]
- internal sealed partial class UserSettings
- {
- [JsonPropertyName("limit")]
- public uint PreferredLimit { get; set; } = 10;
-
- [JsonPropertyName("new_tab")]
- public bool OpenInNewTab { get; set; } = true;
-
- [JsonPropertyName("dark_mode")]
- public bool DarkMode { get; set; } = false;
- }
-}
diff --git a/back-end/src/Cache/UserSettingsStore.cs b/back-end/src/Cache/UserSettingsStore.cs
deleted file mode 100644
index 8887973..0000000
--- a/back-end/src/Cache/UserSettingsStore.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-
-using VNLib.Plugins;
-using VNLib.Plugins.Extensions.Loading;
-using VNLib.Data.Caching;
-using VNLib.Plugins.Extensions.VNCache;
-using VNLib.Plugins.Extensions.VNCache.DataModel;
-
-namespace SimpleBookmark.Cache
-{
-
- [ConfigurationName("settings")]
- internal sealed class UserSettingsStore
- {
- private readonly IEntityCache<UserSettings>? Cache;
-
- public UserSettingsStore(PluginBase plugin, IConfigScope config)
- {
- //try to get the global cache provider
- IGlobalCacheProvider? cache = plugin.GetDefaultGlobalCache();
- if (cache != null)
- {
- MemPackCacheSerializer serializer = new(null);
-
- //Recover the cache prefix
- string prefix = config.GetRequiredProperty("cache_prefix", p => p.GetString()!);
-
- //Create a prefixed cache, then create an entity cache for the user settings
- Cache = cache.GetPrefixedCache(prefix)
- .CreateEntityCache<UserSettings>(serializer, serializer);
- }
- }
- }
-}
diff --git a/back-end/src/Endpoints/BookmarkEndpoint.cs b/back-end/src/Endpoints/BookmarkEndpoint.cs
index 001a41b..19f5118 100644
--- a/back-end/src/Endpoints/BookmarkEndpoint.cs
+++ b/back-end/src/Endpoints/BookmarkEndpoint.cs
@@ -243,20 +243,26 @@ namespace SimpleBookmark.Endpoints
return VirtualClose(entity, webm, HttpStatusCode.UnprocessableEntity);
}
- //See if the uses has reached their quota
- long count = await Bookmarks.GetUserRecordCountAsync(entity.Session.UserID, entity.EventCancellation);
+ /*
+ * Add the new entry to the database if the user is below their quota
+ * and the entry does not already exist by the desired url.
+ */
+ int result = await Bookmarks.AddSingleIfNotExists(
+ entity.Session.UserID,
+ newBookmark,
+ entity.RequestedTimeUtc.DateTime,
+ BmConfig.PerPersonQuota,
+ entity.EventCancellation
+ );
- if(webm.Assert(count <= BmConfig.PerPersonQuota, "You have reached your bookmark quota"))
+ if (webm.Assert(result > -1, "You have reached your bookmark quota"))
{
- return VirtualClose(entity, webm, HttpStatusCode.OK);
- }
-
- //Try to create the record
- ERRNO result = await Bookmarks.CreateUserRecordAsync(newBookmark, entity.Session.UserID, entity.EventCancellation);
+ return VirtualOk(entity, webm);
+ }
- if (webm.Assert(result > 0, "Failed to create new bookmark"))
+ if (webm.Assert(result > 0, "Bookmark with the same url alreay exists"))
{
- return VirtualClose(entity, webm, HttpStatusCode.OK);
+ return VirtualOk(entity, webm);
}
webm.Result = "Successfully created bookmark";
diff --git a/back-end/src/Model/BookmarkStore.cs b/back-end/src/Model/BookmarkStore.cs
index ec020e8..d53ab01 100644
--- a/back-end/src/Model/BookmarkStore.cs
+++ b/back-end/src/Model/BookmarkStore.cs
@@ -52,6 +52,44 @@ namespace SimpleBookmark.Model
existing.Description = newRecord.Description;
existing.JsonTags = newRecord.JsonTags;
}
+
+ public async Task<int> AddSingleIfNotExists(string userId, BookmarkEntry entry, DateTime now, uint maxRecords, CancellationToken cancellation)
+ {
+ ArgumentNullException.ThrowIfNull(userId);
+ ArgumentNullException.ThrowIfNull(entry);
+
+ //Init new db connection
+ await using SimpleBookmarkContext context = new(dbOptions.Value);
+
+ //Check if any bookmarks exist for the user with a given url
+ bool exists = await context.Bookmarks.AnyAsync(b => b.UserId == userId && b.Url == entry.Url, cancellation);
+
+ //If no bookmarks exist, add a new one
+ if (!exists)
+ {
+ //Check if the user has reached the maximum number of bookmarks
+ if (await context.Bookmarks.CountAsync(b => b.UserId == userId, cancellation) >= maxRecords)
+ {
+ await context.SaveAndCloseAsync(true, cancellation);
+ return -1;
+ }
+
+ context.Bookmarks.Add(new ()
+ {
+ Id = GetNewRecordId(), //Overwrite with new record id
+ UserId = userId, //Enforce user id
+ Created = now,
+ LastModified = now,
+ Name = entry.Name, //Copy over the entry data
+ Url = entry.Url,
+ Description = entry.Description,
+ Tags = entry.Tags
+ });
+ }
+
+ await context.SaveAndCloseAsync(true, cancellation);
+ return exists ? 0 : 1; //1 if added, 0 if already exists
+ }
public async Task<BookmarkEntry[]> SearchBookmarksAsync(string userId, string? query, string[] tags, int limit, int page, CancellationToken cancellation)
{
diff --git a/back-end/src/Model/SimpleBookmarkContext.cs b/back-end/src/Model/SimpleBookmarkContext.cs
index 25343d9..f0e53b1 100644
--- a/back-end/src/Model/SimpleBookmarkContext.cs
+++ b/back-end/src/Model/SimpleBookmarkContext.cs
@@ -27,8 +27,6 @@ namespace SimpleBookmark.Model
public DbSet<BookmarkEntry> Bookmarks { get; set; }
- public DbSet<UserSettingsEntry> SbSettings { get; set; }
-
public SimpleBookmarkContext(DbContextOptions options) : base(options)
{ }
@@ -37,43 +35,21 @@ namespace SimpleBookmark.Model
public void OnDatabaseCreating(IDbContextBuilder builder, object? userState)
{
- builder.DefineTable<BookmarkEntry>(nameof(Bookmarks))
- .WithColumn(p => p.Id)
- .SetIsKey()
- .Next()
-
- .WithColumn(p => p.Created)
- .AllowNull(false)
- .Next()
-
- .WithColumn(p => p.LastModified)
- .AllowNull(false)
- .Next()
-
- .WithColumn(p => p.UserId)
- .AllowNull(false)
- .Next()
-
- .WithColumn(p => p.Name)
- .AllowNull(true)
- .Next()
-
- .WithColumn(p => p.Version)
- .TimeStamp()
- .AllowNull(true)
- .Next()
-
- .WithColumn(p => p.Url)
- .AllowNull(true)
- .Next()
-
- .WithColumn(p => p.Description)
- .AllowNull(true)
- .Next()
-
- .WithColumn(p => p.Tags)
- .AllowNull(true)
- .Next();
+ /*
+ * Define the coloumn mappings for the BookmarkEntry table
+ */
+ builder.DefineTable<BookmarkEntry>(nameof(Bookmarks), table =>
+ {
+ table.WithColumn(p => p.Id).AllowNull(false);
+ table.WithColumn(p => p.Created);
+ table.WithColumn(p => p.LastModified);
+ table.WithColumn(p => p.UserId).AllowNull(false);
+ table.WithColumn(p => p.Name);
+ table.WithColumn(p => p.Version);
+ table.WithColumn(p => p.Url);
+ table.WithColumn(p => p.Description);
+ table.WithColumn(p => p.Tags);
+ });
}
}
diff --git a/back-end/src/Model/UserSettingsDbStore.cs b/back-end/src/Model/UserSettingsDbStore.cs
deleted file mode 100644
index d392262..0000000
--- a/back-end/src/Model/UserSettingsDbStore.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-
-using Microsoft.EntityFrameworkCore;
-
-using VNLib.Utils;
-using VNLib.Plugins.Extensions.Loading;
-
-namespace SimpleBookmark.Model
-{
- internal sealed class UserSettingsDbStore(IAsyncLazy<DbContextOptions> dbOptions)
- {
-
- public async Task<UserSettingsEntry?> GetSettingsForUserAsync(string userId, CancellationToken cancellation)
- {
- ArgumentNullException.ThrowIfNull(userId);
-
- //Init new db connection
- await using SimpleBookmarkContext context = new(dbOptions.Value);
-
- UserSettingsEntry? settings = await context.SbSettings.FirstOrDefaultAsync(p => p.UserId == userId, cancellation);
-
- //Close db and commit transaction
- await context.SaveAndCloseAsync(true, cancellation);
-
- return settings;
- }
-
- public async Task<ERRNO> SetSettingsForUser(string userId, UserSettingsEntry settings, CancellationToken cancellation)
- {
- ArgumentNullException.ThrowIfNull(userId);
- ArgumentNullException.ThrowIfNull(settings);
-
- //Init new db connection
- await using SimpleBookmarkContext context = new(dbOptions.Value);
-
- //Search for existing settings entry
- UserSettingsEntry? existing = await context.SbSettings.FirstOrDefaultAsync(p => p.UserId == userId, cancellation);
-
- if (existing is null)
- {
- //Add a new entry
- settings.UserId = userId;
- settings.LastModified = DateTime.UtcNow;
- context.Add(settings);
- }
- else
- {
- //Update existing entry
- existing.SettingsData = settings.SettingsData;
- existing.LastModified = DateTime.UtcNow;
- context.Update(existing);
- }
-
- //Close db and commit transaction
- return await context.SaveAndCloseAsync(true, cancellation);
- }
- }
-}
diff --git a/back-end/src/Model/UserSettingsEntry.cs b/back-end/src/Model/UserSettingsEntry.cs
deleted file mode 100644
index c27af8a..0000000
--- a/back-end/src/Model/UserSettingsEntry.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-using System;
-using System.Text.Json.Serialization;
-using System.ComponentModel.DataAnnotations;
-
-using VNLib.Plugins.Extensions.Data.Abstractions;
-
-namespace SimpleBookmark.Model
-{
- internal sealed class UserSettingsEntry : IUserEntity
- {
- public DateTime LastModified { get; set; }
-
- [Timestamp]
- [JsonIgnore]
- public byte[]? Version { get; set; }
-
- [Key]
- [JsonIgnore]
- public string? UserId { get; set; }
-
- [MaxLength(5000)]
- public byte[]? SettingsData { get; set; }
- }
-}
diff --git a/back-end/src/SimpleBookmark.csproj b/back-end/src/SimpleBookmark.csproj
index 190dc44..d0235a2 100644
--- a/back-end/src/SimpleBookmark.csproj
+++ b/back-end/src/SimpleBookmark.csproj
@@ -34,10 +34,10 @@
<ItemGroup>
<PackageReference Include="MemoryPack" Version="1.21.0" />
- <PackageReference Include="VNLib.Plugins.Extensions.Data" Version="0.1.0-ci0053" />
- <PackageReference Include="VNLib.Plugins.Extensions.Loading" Version="0.1.0-ci0053" />
- <PackageReference Include="VNLib.Plugins.Extensions.Loading.Sql" Version="0.1.0-ci0053" />
- <PackageReference Include="VNLib.Plugins.Extensions.Validation" Version="0.1.0-ci0053" />
+ <PackageReference Include="VNLib.Plugins.Extensions.Data" Version="0.1.0-ci0061" />
+ <PackageReference Include="VNLib.Plugins.Extensions.Loading" Version="0.1.0-ci0061" />
+ <PackageReference Include="VNLib.Plugins.Extensions.Loading.Sql" Version="0.1.0-ci0061" />
+ <PackageReference Include="VNLib.Plugins.Extensions.Validation" Version="0.1.0-ci0061" />
<PackageReference Include="VNLib.Plugins.Extensions.VNCache" Version="0.1.0-ci0054" />
</ItemGroup>