Skip to content

Commit cb34cf5

Browse files
Add database migration, PostgreSQL integration, and update JWT/auth setup
1 parent c771b59 commit cb34cf5

File tree

9 files changed

+205
-18
lines changed

9 files changed

+205
-18
lines changed

Migrations/20251113212512_Init.Designer.cs

Lines changed: 60 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Migrations/20251113212512_Init.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System;
2+
using Microsoft.EntityFrameworkCore.Migrations;
3+
4+
#nullable disable
5+
6+
namespace sparkly_server.Migrations
7+
{
8+
/// <inheritdoc />
9+
public partial class Init : Migration
10+
{
11+
/// <inheritdoc />
12+
protected override void Up(MigrationBuilder migrationBuilder)
13+
{
14+
migrationBuilder.CreateTable(
15+
name: "users",
16+
columns: table => new
17+
{
18+
Id = table.Column<Guid>(type: "uuid", nullable: false),
19+
Email = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
20+
PasswordHash = table.Column<string>(type: "text", nullable: false),
21+
Role = table.Column<string>(type: "text", nullable: false),
22+
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
23+
},
24+
constraints: table =>
25+
{
26+
table.PrimaryKey("PK_users", x => x.Id);
27+
});
28+
29+
migrationBuilder.CreateIndex(
30+
name: "IX_users_Email",
31+
table: "users",
32+
column: "Email",
33+
unique: true);
34+
}
35+
36+
/// <inheritdoc />
37+
protected override void Down(MigrationBuilder migrationBuilder)
38+
{
39+
migrationBuilder.DropTable(
40+
name: "users");
41+
}
42+
}
43+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// <auto-generated />
2+
using System;
3+
using Microsoft.EntityFrameworkCore;
4+
using Microsoft.EntityFrameworkCore.Infrastructure;
5+
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
6+
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
7+
using sparkly_server.Infrastructure;
8+
9+
#nullable disable
10+
11+
namespace sparkly_server.Migrations
12+
{
13+
[DbContext(typeof(AppDbContext))]
14+
partial class AppDbContextModelSnapshot : ModelSnapshot
15+
{
16+
protected override void BuildModel(ModelBuilder modelBuilder)
17+
{
18+
#pragma warning disable 612, 618
19+
modelBuilder
20+
.HasAnnotation("ProductVersion", "9.0.11")
21+
.HasAnnotation("Relational:MaxIdentifierLength", 63);
22+
23+
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
24+
25+
modelBuilder.Entity("sparkly_server.Domain.User", b =>
26+
{
27+
b.Property<Guid>("Id")
28+
.ValueGeneratedOnAdd()
29+
.HasColumnType("uuid");
30+
31+
b.Property<DateTime>("CreatedAt")
32+
.HasColumnType("timestamp with time zone");
33+
34+
b.Property<string>("Email")
35+
.IsRequired()
36+
.HasMaxLength(256)
37+
.HasColumnType("character varying(256)");
38+
39+
b.Property<string>("PasswordHash")
40+
.IsRequired()
41+
.HasColumnType("text");
42+
43+
b.Property<string>("Role")
44+
.IsRequired()
45+
.HasColumnType("text");
46+
47+
b.HasKey("Id");
48+
49+
b.HasIndex("Email")
50+
.IsUnique();
51+
52+
b.ToTable("users", (string)null);
53+
});
54+
#pragma warning restore 612, 618
55+
}
56+
}
57+
}

Program.cs

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,34 @@
11
using Microsoft.AspNetCore.Authentication.JwtBearer;
2+
using Microsoft.EntityFrameworkCore;
23
using Microsoft.IdentityModel.Tokens;
34
using sparkly_server.Enum;
5+
using sparkly_server.Infrastructure;
46
using sparkly_server.Services.Auth;
57
using sparkly_server.Services.Users;
68
using sparkly_server.Services.UserServices;
79
using System.Text;
10+
using Scalar.AspNetCore;
811

912
namespace sparkly_server;
1013

1114
public class Program
1215
{
1316
public static void Main(string[] args)
1417
{
15-
16-
var jwtKey = Environment.GetEnvironmentVariable("SPARKLY_JWT_KEY")!;
17-
var jwtIssuer = Environment.GetEnvironmentVariable("SPARKLY_JWT_ISSUER") ?? "sparkly";
18-
var jwtAudience = Environment.GetEnvironmentVariable("SPARKLY_JWT_AUDIENCE") ?? "sparkly-api";
19-
2018
var builder = WebApplication.CreateBuilder(args);
19+
20+
21+
var jwtKey = builder.Configuration["SPARKLY_JWT_KEY"]
22+
?? Environment.GetEnvironmentVariable("SPARKLY_JWT_KEY")
23+
?? throw new Exception("JWT key missing");
24+
25+
var jwtIssuer = builder.Configuration["SPARKLY_JWT_ISSUER"]
26+
?? Environment.GetEnvironmentVariable("SPARKLY_JWT_ISSUER")
27+
?? "sparkly";
28+
29+
var jwtAudience = builder.Configuration["SPARKLY_JWT_AUDIENCE"]
30+
?? Environment.GetEnvironmentVariable("SPARKLY_JWT_AUDIENCE")
31+
?? "sparkly-api";
2132

2233
builder.Services.AddHttpContextAccessor();
2334

@@ -32,6 +43,15 @@ public static void Main(string[] args)
3243
builder.Services.AddScoped<IJwtProvider, JwtProvider>();
3344
builder.Services.AddScoped<IAuthService, AuthService>();
3445
builder.Services.AddScoped<ICurrentUser, CurrentUser>();
46+
47+
var connectionString = builder.Configuration.GetConnectionString("Default")
48+
?? Environment.GetEnvironmentVariable("ConnectionStrings__Default")
49+
?? throw new Exception("Connection string 'Default' not found.");
50+
51+
builder.Services.AddDbContext<AppDbContext>(options =>
52+
{
53+
options.UseNpgsql(connectionString);
54+
});
3555

3656
builder.Services.AddControllers();
3757
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
@@ -41,15 +61,12 @@ public static void Main(string[] args)
4161
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
4262
.AddJwtBearer(options =>
4363
{
44-
var key = builder.Configuration["SPARKLY_JWT_KEY"]
45-
?? throw new Exception("JWT key missing");
46-
4764
options.TokenValidationParameters = new TokenValidationParameters
4865
{
4966
ValidateIssuer = false,
5067
ValidateAudience = false,
5168
ValidateLifetime = true,
52-
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)),
69+
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey)),
5370
ValidateIssuerSigningKey = true,
5471
ClockSkew = TimeSpan.FromMinutes(1),
5572
};
@@ -61,6 +78,8 @@ public static void Main(string[] args)
6178
if (app.Environment.IsDevelopment())
6279
{
6380
app.MapOpenApi();
81+
82+
app.MapScalarApiReference();
6483
}
6584

6685
app.UseHttpsRedirection();
@@ -70,6 +89,12 @@ public static void Main(string[] args)
7089

7190
app.MapControllers();
7291

92+
using (var scope = app.Services.CreateScope())
93+
{
94+
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
95+
db.Database.Migrate();
96+
}
97+
7398
app.Run();
7499
}
75100
}

appsettings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@
55
"Microsoft.AspNetCore": "Warning"
66
}
77
},
8+
"ConnectionStrings": {
9+
"Default": ""
10+
},
811
"AllowedHosts": "*"
912
}

compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
environment:
55
ASPNETCORE_ENVIRONMENT: ${ASPNETCORE_ENVIRONMENT:-Development}
66
ASPNETCORE_URLS: ${ASPNETCORE_URLS:-http://+:8080}
7-
TRILY_JWT_KEY: ${SPARKLY_JWT_KEY}
7+
SPARKLY_JWT_KEY: ${SPARKLY_JWT_KEY}
88
ConnectionStrings__Default: "Host=pg;Port=5432;Database=sparkly;Username=sparkly;Password=${POSTGRES_PASSWORD}"
99
ports:
1010
- "${API_PORT:-8080}:8080"

sparkly-server.csproj

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@
1313
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.3" />
1414
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.11" />
1515
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.11">
16-
<PrivateAssets>all</PrivateAssets>
1716
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
17+
<PrivateAssets>all</PrivateAssets>
1818
</PackageReference>
19+
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.11" />
1920
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.11">
20-
<PrivateAssets>all</PrivateAssets>
2121
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
22+
<PrivateAssets>all</PrivateAssets>
2223
</PackageReference>
2324
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
25+
<PackageReference Include="Scalar.AspNetCore" Version="2.10.3" />
2426
</ItemGroup>
2527

2628
<ItemGroup>

src/Controllers/ProfileController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace sparkly_server.Controllers
88
{
99
[Authorize]
1010
[ApiController]
11-
[Route("api/v1/[controller]")]
11+
[Route("api/v1/profile")]
1212
public class ProfileController : ControllerBase
1313
{
1414
private readonly ICurrentUser _currentUser;

src/Infrastructure/AppDbContext.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ public class AppDbContext : DbContext
77
{
88
public DbSet<User> Users => Set<User>();
99

10-
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
10+
public AppDbContext(DbContextOptions<AppDbContext> options)
11+
: base(options)
1112
{
1213
}
1314

@@ -30,10 +31,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
3031

3132
cfg.Property(u => u.PasswordHash)
3233
.IsRequired();
33-
34-
cfg.Property(u => u.Role)
35-
.IsRequired()
36-
.HasMaxLength(64);
3734
});
3835
}
3936
}

0 commit comments

Comments
 (0)