diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index ba66cc5..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "dotnet.defaultSolution": "Interlinked.sln" -} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index f8a3e62..0000000 --- a/Dockerfile +++ /dev/null @@ -1,35 +0,0 @@ -FROM mcr.microsoft.com/dotnet/sdk:7.0-alpine AS build - -WORKDIR /source - -COPY Interlinked.sln ./ - -COPY src/Interlinked.Core/*.csproj src/Interlinked.Core/ -COPY src/Interlinked.Shared/*.csproj src/Interlinked.Shared/ -COPY src/Interlinked.User/*.csproj src/Interlinked.User/ -copy test/Interlinked.Test/*.csproj test/Interlinked.Test/ - -RUN dotnet restore - -COPY . . - -RUN dotnet publish ./src/Interlinked.User -c Release -o /build/interlinked - -FROM mcr.microsoft.com/dotnet/aspnet:7.0-alpine AS runtime - - -COPY --from=build /build/interlinked /srv/interlinked - -VOLUME [ "/data", "/srv/log" ] - -WORKDIR /srv/interlinked - -ENV ASPNETCORE_ENVIRONMENT=Production - -# Net - -EXPOSE 80/tcp - -STOPSIGNAL SIGTERM - -ENTRYPOINT [ "dotnet", "/srv/interlinked/Interlinked.User.dll" ] diff --git a/README.md b/README.md index bc6f82d..cca5cf5 100644 --- a/README.md +++ b/README.md @@ -11,3 +11,8 @@ meow ### Health & Wellbeing This solution addresses the issue of social isolation that many developers face, by encouraging socialization with other developers and in-person collaboration. Contact with others is an elemental human need and social isolation may be detrimental to mental health. Encouraging socially active form of software development contributes to a healthy lifestyle. + +## Open Fintech + +Interlinked fosters local development and enables developers to discover and collaborate on local projects. It also enables financial sponsorship of the projects, thus being capable of investing both work and fund for the project. This combined, may increase the success rate of projects, which become community investments. + diff --git a/src/Interlinked.Core/App.razor b/src/Interlinked.Core/App.razor index 1910217..6fd3ed1 100644 --- a/src/Interlinked.Core/App.razor +++ b/src/Interlinked.Core/App.razor @@ -1,6 +1,5 @@  - diff --git a/src/Interlinked.Core/Pages/Dashboard.razor b/src/Interlinked.Core/Pages/Dashboard.razor deleted file mode 100644 index ac386f1..0000000 --- a/src/Interlinked.Core/Pages/Dashboard.razor +++ /dev/null @@ -1,125 +0,0 @@ -@page "/dashboard" -@using System.ComponentModel.DataAnnotations; -@using System.Net -@inject HttpClient req -@inject UserManager usr - -Dashboard - -

Your profile

- -@if (!string.IsNullOrWhiteSpace(_err)) -{ -

@_err

-} - -
-

Profile settings

- -
- - -
-
- - -
-
- - -
- -
-
- -
-

Security settings

- - -
- - -
-
- - -
- -
- - -
- - -
- -
-
- -@code { - private string _err = ""; - private PasswordChangeRequest _pwc = new(); - private EmailChangeRequest _emc = new(); - private ProfileRequest _pdr = new(); - - public record PasswordChangeRequest - { - [Required] - public string PasswordOld { get; set; } = default!; - [Required] - public string PasswordNew { get; set; } = default!; - }; - - public record EmailChangeRequest - { - [Required] - [EmailAddress] - public string Email { get; set; } = default!; - } - - public record ProfileRequest - { - public string? Bio { get; set; } - public string? CC { get; set; } - public string? City { get; set; } - public ICollection Interests { get; set; } = new List(); - } - - protected async override Task OnInitializedAsync() - { - - } - - private async Task ChangePassword() - { - var resp = await req.PostAsJsonAsync("/api/auth/changepass", _pwc); - if (!resp.IsSuccessStatusCode) - { - _err = await resp.Content.ReadAsStringAsync(); - } - this._pwc = new(); - this.StateHasChanged(); - } - - private async Task ChangeEmail() - { - var resp = await req.PostAsJsonAsync("/api/auth/changemail", _emc); - if (!resp.IsSuccessStatusCode) - { - _err = await resp.Content.ReadAsStringAsync(); - } - this._emc = new(); - this.StateHasChanged(); - } - - private async Task UpdateProfile() - { - var resp = await req.PostAsJsonAsync("/api/auth/profile/update", _pdr); - if (!resp.IsSuccessStatusCode) - { - _err = await resp.Content.ReadAsStringAsync(); - } - this._pdr = new(); - this.StateHasChanged(); - } -} diff --git a/src/Interlinked.Core/Pages/FetchData.razor b/src/Interlinked.Core/Pages/FetchData.razor new file mode 100644 index 0000000..783a026 --- /dev/null +++ b/src/Interlinked.Core/Pages/FetchData.razor @@ -0,0 +1,57 @@ +@page "/fetchdata" +@inject HttpClient Http + +Weather forecast + +

Weather forecast

+ +

This component demonstrates fetching data from the server.

+ +@if (forecasts == null) +{ +

Loading...

+} +else +{ + + + + + + + + + + + @foreach (var forecast in forecasts) + { + + + + + + + } + +
DateTemp. (C)Temp. (F)Summary
@forecast.Date.ToShortDateString()@forecast.TemperatureC@forecast.TemperatureF@forecast.Summary
+} + +@code { + private WeatherForecast[]? forecasts; + + protected override async Task OnInitializedAsync() + { + forecasts = await Http.GetFromJsonAsync("sample-data/weather.json"); + } + + public class WeatherForecast + { + public DateOnly Date { get; set; } + + public int TemperatureC { get; set; } + + public string? Summary { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + } +} diff --git a/src/Interlinked.Core/Pages/Index.razor b/src/Interlinked.Core/Pages/Index.razor index 11e8c58..4b1bf7c 100644 --- a/src/Interlinked.Core/Pages/Index.razor +++ b/src/Interlinked.Core/Pages/Index.razor @@ -16,9 +16,15 @@ -@code { +@code{ + public class City + { + public double Latitude { get; set; } + public double Longitude { get; set; } + public string Name { get; set; } + } private List Cities = new List { - new City { Latitude = 34.060620, Longitude = -118.330491, Name="California" }, - new City{ Latitude = 40.724546, Longitude = -73.850344, Name="New York"} + new City { Latitude = 34.060620, Longitude = -118.330491, Name="California" }, + new City{ Latitude = 40.724546, Longitude = -73.850344, Name="New York"} }; -} +} \ No newline at end of file diff --git a/src/Interlinked.Core/Pages/Login.razor b/src/Interlinked.Core/Pages/Login.razor index a72492f..f42069c 100644 --- a/src/Interlinked.Core/Pages/Login.razor +++ b/src/Interlinked.Core/Pages/Login.razor @@ -40,15 +40,7 @@ public LoginModel Model { get; set; } = new(); public string ValidationMsg = string.Empty; - protected async override Task OnInitializedAsync() - { - if (await usr.GetUser() != null) - { - nav.NavigateTo("/"); - return; - } - Model ??= new(); - } + protected override void OnInitialized() => Model ??= new(); private async Task Submit() { @@ -64,9 +56,9 @@ this.StateHasChanged(); return; } - usr.SetUser(user); + usr.User = user; this.StateHasChanged(); - nav.NavigateTo("/", true); + nav.NavigateTo("/"); return; } diff --git a/src/Interlinked.Core/Pages/Logout.razor b/src/Interlinked.Core/Pages/Logout.razor index 86a6d19..099565f 100644 --- a/src/Interlinked.Core/Pages/Logout.razor +++ b/src/Interlinked.Core/Pages/Logout.razor @@ -10,9 +10,8 @@ var resp = await req.GetAsync("/api/auth/logout"); if (resp.StatusCode == HttpStatusCode.NoContent) { - usr.SetUser(null!); + usr.User = null!; } - this.StateHasChanged(); - nav.NavigateTo("/login", true); + nav.NavigateTo("/login"); } } diff --git a/src/Interlinked.Core/Pages/PeopleTable.razor b/src/Interlinked.Core/Pages/PeopleTable.razor deleted file mode 100644 index 007fdab..0000000 --- a/src/Interlinked.Core/Pages/PeopleTable.razor +++ /dev/null @@ -1,34 +0,0 @@ -@page "/peopletable" - -

Employee Information

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameSurnameCityCountryProficiencies
JohnDoeNew YorkUSAWeb Development
JaneSmithLos AngelesUSAGraphic Design
MariaGarciaMadridSpainData Analysis
\ No newline at end of file diff --git a/src/Interlinked.Core/Pages/Register.razor b/src/Interlinked.Core/Pages/Register.razor index 435b3da..f23f15f 100644 --- a/src/Interlinked.Core/Pages/Register.razor +++ b/src/Interlinked.Core/Pages/Register.razor @@ -52,15 +52,7 @@ public LoginModel Model { get; set; } = new(); public string ValidationMsg = string.Empty; - protected override async Task OnInitializedAsync() - { - if (await usr.GetUser() != null) - { - nav.NavigateTo("/", true); - return; - } - Model ??= new(); - } + protected override void OnInitialized() => Model ??= new(); private async Task Submit() { @@ -75,9 +67,9 @@ this.StateHasChanged(); return; } - usr.SetUser(user); + usr.User = user; this.StateHasChanged(); - nav.NavigateTo("/", true); + nav.NavigateTo("/"); return; } diff --git a/src/Interlinked.Core/Pages/UserProfile.razor b/src/Interlinked.Core/Pages/UserProfile.razor index f5556de..4abfa97 100644 --- a/src/Interlinked.Core/Pages/UserProfile.razor +++ b/src/Interlinked.Core/Pages/UserProfile.razor @@ -1,66 +1,26 @@ -@page "/profile/{username}" -@inject HttpClient cli +@page "/user/{username}" @code { [Parameter] public string Username { get; set; } = "johndoeUwU"; - private UserModel _user = null!; - private bool _valid = true; + private string FullName = "meow uwu"; + private string Bio = "Software Developer"; + private List Skills = new List { "C#", "ASP.NET Core", "Blazor" }; } -@if (!_valid) -{ -

User not found @(":<")

-} -else -{ - if (_user != null) - { - +

@Bio

+

Skills

+
    + @foreach (var skill in Skills) { - _valid = false; - return; +
  • @skill
  • } - - _user = (await resp.Content.ReadFromJsonAsync())!; - this.StateHasChanged(); - } -} +
+ diff --git a/src/Interlinked.Core/Program.cs b/src/Interlinked.Core/Program.cs index 4375fb2..672e462 100644 --- a/src/Interlinked.Core/Program.cs +++ b/src/Interlinked.Core/Program.cs @@ -27,6 +27,8 @@ internal class Program var app = builder.Build(); + await app.Services.GetRequiredService().InitAsync(); + await builder.Build().RunAsync(); } } diff --git a/src/Interlinked.Core/Services/UserManager.cs b/src/Interlinked.Core/Services/UserManager.cs index 16dfc69..4f1de42 100644 --- a/src/Interlinked.Core/Services/UserManager.cs +++ b/src/Interlinked.Core/Services/UserManager.cs @@ -16,49 +16,17 @@ public class UserManager } private readonly IServiceProvider _serv; - private bool _init = false; - static SemaphoreSlim sem = new SemaphoreSlim(1, 1); - public async Task InitAsync() { - await sem.WaitAsync(); - if (_init) - { - sem.Release(); - return; - } - using var scope = _serv.CreateAsyncScope(); var resp = await scope.ServiceProvider.GetRequiredService().GetAsync("/api/auth/userdata"); if (resp.StatusCode == HttpStatusCode.OK) { - this.User = (await resp.Content.ReadFromJsonAsync())!; - Console.WriteLine($"User: {User.Id}"); + User = (await resp.Content.ReadFromJsonAsync())!; } - - _init = true; - - sem.Release(); } - private UserModel User { get; set; } = default!; - public async Task GetUser() - { - if (User == null) - { - if (!_init) - { - await InitAsync(); - } - } - - return User; - } - - public void SetUser(UserModel u) - { - User = u; - } + public UserModel User { get; set; } = default!; public bool IsAuthorized => User != null; } diff --git a/src/Interlinked.Core/Shared/AuthenticateUser.razor b/src/Interlinked.Core/Shared/AuthenticateUser.razor deleted file mode 100644 index ed02d34..0000000 --- a/src/Interlinked.Core/Shared/AuthenticateUser.razor +++ /dev/null @@ -1,10 +0,0 @@ -@inject UserManager usr - -@code { - protected override async Task OnInitializedAsync() - { - await Task.Yield(); - await usr.InitAsync(); - this.StateHasChanged(); - } -} diff --git a/src/Interlinked.Core/Shared/MainLayout.razor b/src/Interlinked.Core/Shared/MainLayout.razor index ae76f24..d6d6eda 100644 --- a/src/Interlinked.Core/Shared/MainLayout.razor +++ b/src/Interlinked.Core/Shared/MainLayout.razor @@ -8,14 +8,14 @@
- @if (u == null) + @if (!usr.IsAuthorized) { Log in Register } else { - Log out (@u?.Username) + Log out (@usr.User.Username) }
@@ -24,12 +24,3 @@
- -@code { - private UserModel u = null!; - protected override async Task OnInitializedAsync() - { - await Task.Yield(); - u = (await usr.GetUser())!; - } -} diff --git a/src/Interlinked.Core/Shared/MainLayout.razor.css b/src/Interlinked.Core/Shared/MainLayout.razor.css index deec2fe..c182629 100644 --- a/src/Interlinked.Core/Shared/MainLayout.razor.css +++ b/src/Interlinked.Core/Shared/MainLayout.razor.css @@ -1,85 +1,83 @@ .page { - position: relative; - display: flex; - flex-direction: column; + position: relative; + display: flex; + flex-direction: column; } main { - flex: 1; + flex: 1; } .sidebar { - background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); + background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); } + + .top-row { - background-color: #f7f7f7; - border-bottom: 1px solid #d6d5d5; - justify-content: flex-end; - height: 3.5rem; - display: flex; - align-items: center; + background-color: #f7f7f7; + border-bottom: 1px solid #d6d5d5; + justify-content: flex-end; + height: 3.5rem; + display: flex; + align-items: center; } -.top-row ::deep a, -.top-row ::deep .btn-link { - white-space: nowrap; - margin-left: 1.5rem; - text-decoration: none; -} + .top-row ::deep a, .top-row ::deep .btn-link { + white-space: nowrap; + margin-left: 1.5rem; + text-decoration: none; + } -.top-row ::deep a:hover, -.top-row ::deep .btn-link:hover { - text-decoration: underline; -} + .top-row ::deep a:hover, .top-row ::deep .btn-link:hover { + text-decoration: underline; + } -.top-row ::deep a:first-child { - overflow: hidden; - text-overflow: ellipsis; -} + .top-row ::deep a:first-child { + overflow: hidden; + text-overflow: ellipsis; + } @media (max-width: 640.98px) { - .top-row:not(.auth) { - display: none; - } + .top-row:not(.auth) { + display: none; + } - .top-row.auth { - justify-content: space-between; - } + .top-row.auth { + justify-content: space-between; + } - .top-row ::deep a, - .top-row ::deep .btn-link { - margin-left: 0; - } + .top-row ::deep a, .top-row ::deep .btn-link { + margin-left: 0; + } } @media (min-width: 641px) { - .page { - flex-direction: row; - } + .page { + flex-direction: row; + } - .sidebar { - width: 250px; - height: 100vh; - position: sticky; - top: 0; - } + .sidebar { + width: 250px; + height: 100vh; + position: sticky; + top: 0; + } - .top-row { - position: sticky; - top: 0; - z-index: 20; - } + .top-row { + position: sticky; + top: 0; + z-index: 1; + } - .top-row.auth ::deep a:first-child { - flex: 1; - text-align: right; - width: 0; - } + .top-row.auth ::deep a:first-child { + flex: 1; + text-align: right; + width: 0; + } - .top-row, - article { - padding-left: 2rem !important; - padding-right: 1.5rem !important; - } + .top-row, article { + padding-left: 2rem !important; + padding-right: 1.5rem !important; + } } diff --git a/src/Interlinked.Core/Shared/MainLayoutLanding.razor b/src/Interlinked.Core/Shared/MainLayoutLanding.razor deleted file mode 100644 index c5f2682..0000000 --- a/src/Interlinked.Core/Shared/MainLayoutLanding.razor +++ /dev/null @@ -1,23 +0,0 @@ -@inherits LayoutComponentBase -@inject UserManager usr - -
- -
-
- @if (!usr.IsAuthorized) - { - Log in - Register - } - else - { - Log out (async () => (await @usr.GetUser()).Username) - } -
- -
- @Body -
-
-
diff --git a/src/Interlinked.Core/Shared/MainLayoutLanding.razor.css b/src/Interlinked.Core/Shared/MainLayoutLanding.razor.css deleted file mode 100644 index ff95d37..0000000 --- a/src/Interlinked.Core/Shared/MainLayoutLanding.razor.css +++ /dev/null @@ -1,89 +0,0 @@ -.page { - position: relative; - display: flex; - flex-direction: column; -} - -main { - flex: 1; -} - -.top-row { - z-index: 20; - background-color: #f7f7f7; - border-bottom: 1px solid #d6d5d5; - justify-content: flex-end; - height: 3.5rem; - display: flex; - align-items: center; -} - -.top-row ::deep a, -.top-row ::deep .btn-link { - white-space: nowrap; - margin-left: 1.5rem; - text-decoration: none; -} - -.top-row ::deep a:hover, -.top-row ::deep .btn-link:hover { - text-decoration: underline; -} - -.top-row ::deep a:first-child { - overflow: hidden; - text-overflow: ellipsis; -} - -@media (max-width: 640.98px) { - .top-row:not(.auth) { - display: none; - } - - .top-row.auth { - justify-content: space-between; - } - - .top-row ::deep a, - .top-row ::deep .btn-link { - margin-left: 0; - } -} - -@media (min-width: 641px) { - .page { - flex-direction: row; - } - - .sidebar { - width: 250px; - height: 100vh; - position: sticky; - top: 0; - } - - .top-row { - position: sticky; - top: 0; - z-index: 20; - } - - .top-row.auth ::deep a:first-child { - flex: 1; - text-align: right; - width: 0; - } - - .top-row, - article { - padding-left: 2rem !important; - padding-right: 1.5rem !important; - } -} - -.form { - min-width: 100%; - min-height: 100%; - flex-wrap: wrap; - flex-direction: column; -} diff --git a/src/Interlinked.Core/Shared/NavMenu.razor b/src/Interlinked.Core/Shared/NavMenu.razor index 508b931..2c519f1 100644 --- a/src/Interlinked.Core/Shared/NavMenu.razor +++ b/src/Interlinked.Core/Shared/NavMenu.razor @@ -1,9 +1,6 @@ -@inject UserManager usr - -