Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
abd8d32
add dev settings and feature flags for posts
NielsPilgaard Aug 30, 2024
8b0ca9d
make 90% of the backend for posts (not groupposts yet)
NielsPilgaard Aug 30, 2024
e12efcc
add error handling
NielsPilgaard Aug 30, 2024
7797602
add todos
NielsPilgaard Aug 30, 2024
1bf2dc8
initial draft of the post page, mostly copy paste
NielsPilgaard Aug 30, 2024
bcff743
split into components
NielsPilgaard Sep 1, 2024
f8851b9
more post work
NielsPilgaard Sep 1, 2024
db5b46a
Update CreatePostComponent.razor
NielsPilgaard Sep 1, 2024
17aa5e7
fixes
NielsPilgaard Sep 3, 2024
8a40302
register post services
NielsPilgaard Sep 14, 2024
14031d3
Merge branch 'main' into feature/posts
NielsPilgaard Dec 8, 2024
060c01f
Merge branch 'main' into feature/posts
NielsPilgaard Dec 15, 2024
a8cf723
remove lighthouse CI
NielsPilgaard Dec 15, 2024
1c724b6
Merge branch 'main' into feature/posts
NielsPilgaard Dec 15, 2024
0ac19b4
Merge branch 'main' into feature/posts
NielsPilgaard Jan 6, 2025
2595509
Merge branch 'main' into feature/posts
NielsPilgaard Feb 18, 2025
3ab038e
Remove Jordnaer.Shared.Infrastructure
NielsPilgaard Feb 20, 2025
ed9804d
Create add-migration.ps1
NielsPilgaard Feb 20, 2025
b75a503
add migration
NielsPilgaard Feb 20, 2025
7dbfb7d
update drop_all_tables
NielsPilgaard Feb 20, 2025
605fe5f
add index on zipcode for posts
NielsPilgaard Feb 20, 2025
3716aca
Switch to in-memory mass transit
NielsPilgaard Feb 20, 2025
f72462f
Update WebApplicationBuilderExtensions.cs
NielsPilgaard Feb 23, 2025
ae67e13
Update PostSearchService.cs
NielsPilgaard Feb 23, 2025
7d396f6
Update PostService.cs
NielsPilgaard Feb 23, 2025
b119403
Merge branch 'main' into feature/posts
NielsPilgaard Feb 23, 2025
edfb6e1
Merge branch 'main' into feature/posts
NielsPilgaard Feb 23, 2025
2472994
Merge branch 'main' into feature/posts
NielsPilgaard Feb 23, 2025
b527645
Update ChatNotificationService.cs
NielsPilgaard Feb 23, 2025
cb4bde8
tiny refactors
NielsPilgaard Feb 23, 2025
c3d2e6d
remove interface we don't need
NielsPilgaard Feb 23, 2025
1a68118
add category for test purposes
NielsPilgaard Feb 23, 2025
87abebe
simplify
NielsPilgaard Feb 23, 2025
4b23dea
Merge branch 'main' into feature/posts
NielsPilgaard Feb 25, 2025
67cb945
category search bugfix for posts aswell
NielsPilgaard Feb 25, 2025
6af6226
Merge branch 'main' into feature/posts
NielsPilgaard Feb 25, 2025
a4f632a
Merge branch 'main' into feature/posts
NielsPilgaard Mar 15, 2025
f4486da
retry csproj merge
NielsPilgaard Mar 15, 2025
5eb95ea
Merge branch 'main' into feature/posts
NielsPilgaard Mar 25, 2025
0093ec5
Update Jordnaer.csproj
NielsPilgaard Mar 25, 2025
a14292d
clear unused usings (merge misshap)
NielsPilgaard Mar 25, 2025
c06fce2
minor improvements here and there
NielsPilgaard Mar 25, 2025
5683015
Merge branch 'main' into feature/posts
NielsPilgaard Aug 9, 2025
3400368
update nugets
NielsPilgaard Aug 9, 2025
566cd50
fix e2e tests looking for old placeholder
NielsPilgaard Aug 13, 2025
09ce194
Create EnumExtensions.cs
NielsPilgaard Aug 13, 2025
6499500
Fix Group Members page to allow updates
NielsPilgaard Aug 29, 2025
48a380b
update nugets
NielsPilgaard Aug 29, 2025
9988770
move logout button to profile page
NielsPilgaard Aug 29, 2025
2353fd9
improve ux
NielsPilgaard Aug 29, 2025
3ce112b
add safety
NielsPilgaard Aug 29, 2025
40719f2
remove redundant enum extensions class
NielsPilgaard Aug 29, 2025
7977f5c
Update website_frontend_ci.yml
NielsPilgaard Aug 29, 2025
fce1059
Update Jordnaer.E2E.Tests.csproj
NielsPilgaard Aug 29, 2025
32d9c58
Merge branch 'main' into feature/posts
NielsPilgaard Aug 29, 2025
ca4fcc8
Update _Imports.razor
NielsPilgaard Aug 29, 2025
319e1d7
Merge branch 'feature/posts' of https://github.com/NielsPilgaard/Jord…
NielsPilgaard Aug 29, 2025
f3ea4fa
cleanup save/revert code
NielsPilgaard Aug 29, 2025
e16532c
Update website_frontend_ci.yml
NielsPilgaard Aug 29, 2025
e72cfb9
Update website_frontend_ci.yml
NielsPilgaard Aug 29, 2025
8e7b8f5
safer OnInitializedAsync
NielsPilgaard Aug 29, 2025
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
4 changes: 2 additions & 2 deletions .github/workflows/website_frontend_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ env:
jobs:
playwright:
# Only run this if the workflow that triggered it was successful
if: ${{ github.event.workflow_run.conclusion == 'success' }}
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright/dotnet:v1.50.0-jammy
image: mcr.microsoft.com/playwright/dotnet:v1.54.0-jammy
options: --user 1001
steps:
- name: Checkout
Expand Down
25 changes: 2 additions & 23 deletions Jordnaer.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04718F38-85FB-4998-B2FF-AA5B8999BA5D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EF8561E8-6A1E-4ED0-851A-913EEC801AFA}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
Directory.Build.props = Directory.Build.props
.github\workflows\github-release.yml = .github\workflows\github-release.yml
.github\workflows\lighthouse.yml = .github\workflows\lighthouse.yml
README.md = README.md
.github\workflows\website_backend_ci.yml = .github\workflows\website_backend_ci.yml
.github\workflows\website_cd.yml = .github\workflows\website_cd.yml
Expand All @@ -28,16 +25,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{29332986-7
docs\invite.md = docs\invite.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "web", "web", "{7326F14D-ADB6-4CB0-9AE4-2717133CED27}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{B7172579-75AE-4D50-9328-3B0D80252384}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "web", "web", "{B4EAF579-8327-4B92-8357-8FF12C21755F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{659DB215-49CE-4C57-8823-56AFAE2DED72}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jordnaer.Shared.Infrastructure", "src\shared\Jordnaer.Shared.Infrastructure\Jordnaer.Shared.Infrastructure.csproj", "{73928908-776A-4AE3-98A7-AAB82A9A9C19}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jordnaer.Shared", "src\shared\Jordnaer.Shared\Jordnaer.Shared.csproj", "{41CAB9C0-E554-4F17-8C8D-AD50EF22B70B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jordnaer.E2E.Tests", "tests\web\Jordnaer.E2E.Tests\Jordnaer.E2E.Tests.csproj", "{D17408FE-1231-4CEC-8C7F-773915B70242}"
Expand All @@ -54,10 +43,6 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{73928908-776A-4AE3-98A7-AAB82A9A9C19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{73928908-776A-4AE3-98A7-AAB82A9A9C19}.Debug|Any CPU.Build.0 = Debug|Any CPU
{73928908-776A-4AE3-98A7-AAB82A9A9C19}.Release|Any CPU.ActiveCfg = Release|Any CPU
{73928908-776A-4AE3-98A7-AAB82A9A9C19}.Release|Any CPU.Build.0 = Release|Any CPU
{41CAB9C0-E554-4F17-8C8D-AD50EF22B70B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{41CAB9C0-E554-4F17-8C8D-AD50EF22B70B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{41CAB9C0-E554-4F17-8C8D-AD50EF22B70B}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -83,14 +68,8 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{7326F14D-ADB6-4CB0-9AE4-2717133CED27} = {04718F38-85FB-4998-B2FF-AA5B8999BA5D}
{B4EAF579-8327-4B92-8357-8FF12C21755F} = {3F3B23F8-EA95-44B5-B907-5E772A2660E2}
{659DB215-49CE-4C57-8823-56AFAE2DED72} = {04718F38-85FB-4998-B2FF-AA5B8999BA5D}
{73928908-776A-4AE3-98A7-AAB82A9A9C19} = {659DB215-49CE-4C57-8823-56AFAE2DED72}
{41CAB9C0-E554-4F17-8C8D-AD50EF22B70B} = {659DB215-49CE-4C57-8823-56AFAE2DED72}
{D17408FE-1231-4CEC-8C7F-773915B70242} = {B4EAF579-8327-4B92-8357-8FF12C21755F}
{06B65FD2-ABF3-4D58-9655-375C0C57B3C3} = {7326F14D-ADB6-4CB0-9AE4-2717133CED27}
{26821232-1D4D-4CA8-AA41-7605C42C373A} = {B4EAF579-8327-4B92-8357-8FF12C21755F}
{D17408FE-1231-4CEC-8C7F-773915B70242} = {3F3B23F8-EA95-44B5-B907-5E772A2660E2}
{26821232-1D4D-4CA8-AA41-7605C42C373A} = {3F3B23F8-EA95-44B5-B907-5E772A2660E2}
{3C1DA78A-722B-485E-9D60-CC19ACFDA892} = {B7172579-75AE-4D50-9328-3B0D80252384}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/Jordnaer.Benchmarks/Jordnaer.Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.15.2" />
<PackageReference Include="Bogus" Version="35.6.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.8" />
</ItemGroup>

<ItemGroup>
Expand Down

This file was deleted.

4 changes: 2 additions & 2 deletions src/shared/Jordnaer.Shared/Database/GroupCategory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ namespace Jordnaer.Shared;

public class GroupCategory
{
public required Guid GroupId { get; set; }
public required Guid GroupId { get; set; }

public required int CategoryId { get; set; }
public required int CategoryId { get; set; }
}
30 changes: 30 additions & 0 deletions src/shared/Jordnaer.Shared/Database/GroupPost.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;

namespace Jordnaer.Shared;

public class GroupPost
{

[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public required Guid Id { get; init; }

[StringLength(1000, ErrorMessage = "Opslag må højest være 1000 karakterer lang.")]
[Required(AllowEmptyStrings = false, ErrorMessage = "Opslag skal have mindst 1 karakter.")]
public required string Text { get; init; }

public DateTimeOffset CreatedUtc { get; init; } = DateTimeOffset.UtcNow;

public int? ZipCode { get; set; }

[ForeignKey(nameof(UserProfile))]
public required string UserProfileId { get; init; } = null!;

public UserProfile UserProfile { get; init; } = null!;

[ForeignKey(nameof(Group))]
public required Guid GroupId { get; init; }

public Group Group { get; init; } = null!;
}
30 changes: 30 additions & 0 deletions src/shared/Jordnaer.Shared/Database/Post.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;

namespace Jordnaer.Shared;

[Index(nameof(ZipCode))]
public class Post
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public required Guid Id { get; init; }

[StringLength(1000, ErrorMessage = "Opslag må højest være 1000 karakterer lang.")]
[Required(AllowEmptyStrings = false, ErrorMessage = "Opslag skal have mindst 1 karakter.")]
public required string Text { get; set; }

public DateTimeOffset CreatedUtc { get; set; } = DateTimeOffset.UtcNow;

public int? ZipCode { get; set; }

public string? City { get; set; }

[ForeignKey(nameof(UserProfile))]
public required string UserProfileId { get; set; } = null!;

public UserProfile UserProfile { get; init; } = null!;

public List<Category> Categories { get; set; } = [];
}
8 changes: 8 additions & 0 deletions src/shared/Jordnaer.Shared/Database/PostCategory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Jordnaer.Shared;

public class PostCategory
{
public required Guid PostId { get; set; }

public required int CategoryId { get; set; }
}
16 changes: 8 additions & 8 deletions src/shared/Jordnaer.Shared/Extensions/EnumExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Jordnaer.Shared.Extensions;
public static class EnumExtensions
{
public static DisplayAttribute? GetDisplayAttribute(this Enum enumValue)
{
return enumValue.GetType()
.GetField(enumValue.ToString())?.GetCustomAttribute<DisplayAttribute>();
.GetField(enumValue.ToString())?
.GetCustomAttribute<DisplayAttribute>();
}

public static string GetDisplayName(this Enum enumValue)
{
return enumValue.GetDisplayAttribute()?.Name ?? enumValue.ToString();
}

public static string? ToDisplayName<T>(this T enumValue) where T : Enum =>
enumValue.GetDisplayAttribute()?
.GetName();
}
24 changes: 24 additions & 0 deletions src/shared/Jordnaer.Shared/Extensions/PostExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace Jordnaer.Shared;

public static class PostExtensions
{
public static PostDto ToPostDto(this Post post)
{
return new PostDto
{
Id = post.Id,
Text = post.Text,
CreatedUtc = post.CreatedUtc,
Author = new UserSlim
{
Id = post.UserProfileId,
ProfilePictureUrl = post.UserProfile.ProfilePictureUrl,
UserName = post.UserProfile.UserName,
DisplayName = post.UserProfile.DisplayName
},
City = post.City,
ZipCode = post.ZipCode,
Categories = post.Categories.Select(category => category.Name).ToList()
};
}
}
14 changes: 7 additions & 7 deletions src/shared/Jordnaer.Shared/Jordnaer.Shared.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="9.0.7" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.7" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.7" />
<PackageReference Include="Microsoft.Extensions.Options.DataAnnotations" Version="9.0.7" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.7.0" />
<PackageReference Include="JetBrains.Annotations" Version="2025.2.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="9.0.8" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.8" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.8" />
<PackageReference Include="Microsoft.Extensions.Options.DataAnnotations" Version="9.0.8" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.8.0" />
<PackageReference Include="NetEscapades.EnumGenerators" Version="1.0.0-beta12" />
<PackageReference Include="Refit.HttpClientFactory" Version="8.0.0" />
<PackageReference Include="MassTransit.Abstractions" Version="8.5.1" />
<PackageReference Include="MassTransit.Abstractions" Version="8.5.2" />
</ItemGroup>

<ItemGroup>
Expand Down
21 changes: 21 additions & 0 deletions src/shared/Jordnaer.Shared/Posts/PostDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.ComponentModel.DataAnnotations;

namespace Jordnaer.Shared;

public class PostDto
{
public required Guid Id { get; init; }

[StringLength(1000, ErrorMessage = "Opslag må højest være 1000 karakterer lang.")]
[Required(AllowEmptyStrings = false, ErrorMessage = "Opslag skal have mindst 1 karakter.")]
public required string Text { get; init; }

public int? ZipCode { get; set; }
public string? City { get; set; }

public DateTimeOffset CreatedUtc { get; init; }

public required UserSlim Author { get; init; }

public List<string> Categories { get; set; } = [];
}
57 changes: 57 additions & 0 deletions src/shared/Jordnaer.Shared/Posts/PostSearchFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System.ComponentModel.DataAnnotations;

namespace Jordnaer.Shared;

public class PostSearchFilter
{
public string? Contents { get; set; }
public string[]? Categories { get; set; } = [];

/// <summary>
/// Only show user results within this many kilometers of the <see cref="Location"/>.
/// </summary>
[Range(1, 50, ErrorMessage = "Afstand skal være mellem 1 og 50 km")]
[LocationRequired]
public int? WithinRadiusKilometers { get; set; }

[RadiusRequired]
public string? Location { get; set; }

public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 10;
}

file class RadiusRequiredAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object? value, ValidationContext validationContext)
{
var postSearchFilter = (PostSearchFilter)validationContext.ObjectInstance;

if (postSearchFilter.WithinRadiusKilometers is null && string.IsNullOrEmpty(postSearchFilter.Location))
{
return ValidationResult.Success!;
}

return postSearchFilter.WithinRadiusKilometers is null
? new ValidationResult("Radius skal vælges når et område er valgt.")
: ValidationResult.Success!;
}
}
Comment thread
NielsPilgaard marked this conversation as resolved.

file class LocationRequiredAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object? value, ValidationContext validationContext)
{
var postSearchFilter = (PostSearchFilter)validationContext.ObjectInstance;

if (postSearchFilter.WithinRadiusKilometers is null && string.IsNullOrEmpty(postSearchFilter.Location))
{
return ValidationResult.Success!;

}

return string.IsNullOrEmpty(postSearchFilter.Location)
? new ValidationResult("Område skal vælges når en radius er valgt.")
: ValidationResult.Success!;
}
}
Comment thread
NielsPilgaard marked this conversation as resolved.
7 changes: 7 additions & 0 deletions src/shared/Jordnaer.Shared/Posts/PostSearchResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Jordnaer.Shared;

public class PostSearchResult
{
public List<PostDto> Posts { get; set; } = [];
public int TotalCount { get; set; }
}
22 changes: 21 additions & 1 deletion src/web/Jordnaer/Database/JordnaerDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class JordnaerDbContext : IdentityDbContext<ApplicationUser>
public DbSet<Category> Categories { get; set; } = default!;
public DbSet<UserProfileCategory> UserProfileCategories { get; set; } = default!;
public DbSet<UserContact> UserContacts { get; set; } = default!;
public DbSet<Shared.Chat> Chats { get; set; } = default!;
public DbSet<Chat> Chats { get; set; } = default!;
public DbSet<ChatMessage> ChatMessages { get; set; } = default!;
public DbSet<UnreadMessage> UnreadMessages { get; set; } = default;
public DbSet<UserChat> UserChats { get; set; } = default!;
Expand All @@ -20,8 +20,28 @@ public class JordnaerDbContext : IdentityDbContext<ApplicationUser>
public DbSet<GroupMembership> GroupMemberships { get; set; } = default!;
public DbSet<GroupCategory> GroupCategories { get; set; } = default!;

public DbSet<Post> Posts { get; set; } = default!;
public DbSet<GroupPost> GroupPosts { get; set; } = default!;

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.HasOne(e => e.UserProfile)
.WithMany();

modelBuilder.Entity<Post>()
.HasMany(e => e.Categories)
.WithMany()
.UsingEntity<PostCategory>();

modelBuilder.Entity<GroupPost>()
.HasOne(e => e.UserProfile)
.WithMany();

modelBuilder.Entity<GroupPost>()
.HasOne(e => e.Group)
.WithMany();

modelBuilder.Entity<Group>()
.HasMany(e => e.Members)
.WithMany(e => e.Groups)
Expand Down
Loading