.dockerignore
+1
-0
diff --git a/.dockerignore b/.dockerignore
index 64e3cd5..f8745e7 100644
@@ -492,3 +492,4 @@ git-daemon-export-ok
# Development files
blobs
database.db*
.gitignore
+3
-0
diff --git a/.gitignore b/.gitignore
index 3b15c69..b3c31ed 100644
@@ -482,3 +482,6 @@ $RECYCLE.BIN/
# Vim temporary swap files
*.swp
# Development files
database.db*
Directory.Packages.props
+9
-0
diff --git a/Directory.Packages.props b/Directory.Packages.props
index dfdf6c6..a04bba8 100644
@@ -10,9 +10,18 @@
</GlobalPackageReference>
</ItemGroup>
<ItemGroup>
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.7">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageVersion>
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.7" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.2" />
<PackageVersion
Include="OpenTelemetry.Instrumentation.EntityFrameworkCore"
Version="1.15.1-beta.1"
/>
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.15.1" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.15.1" />
</ItemGroup>
MatDenDagen/Components/Pages/Admin/Questions.razor
+84
-0
diff --git a/MatDenDagen/Components/Pages/Admin/Questions.razor b/MatDenDagen/Components/Pages/Admin/Questions.razor
new file mode 100644
index 0000000..7480d15
@@ -0,0 +1,84 @@
@page "/admin/questions"
@using MatDenDagen.Infrastructure.Storage.Database
@using MatDenDagen.Models
@using Microsoft.EntityFrameworkCore
@inject TimeProvider timeProvider
@inject QuestionnaireContext questionnaireContext
<ul>
@foreach (var question in questionnaireContext.Questions)
{
<li>
<span>@question.Text</span>
<EditForm FormName="@($"RemoveQuestion-{question.Id}")" Model="@removeQuestionModel" OnSubmit="@RemoveQuestion"
Enhance>
<input type="hidden" name="removeQuestionModel.QuestionId" value="@question.Id" />
<input type="submit" value="Ta bort" />
</EditForm>
</li>
}
</ul>
<hr />
<EditForm FormName="AddQuestion" Model="@addQuestionModel" OnSubmit="@AddQuestion" Enhance>
<p>
<label>
<span>Fråga:</span>
<input type="text" name="addQuestionModel.Text" required />
</label>
</p>
<p>
<input type="submit" value="Lägg till" />
</p>
</EditForm>
@code {
[SupplyParameterFromForm]
private AddQuestionModel? addQuestionModel { get; set; }
[SupplyParameterFromForm]
private RemoveQuestionModel? removeQuestionModel { get; set; }
protected override void OnInitialized()
{
addQuestionModel ??= new();
removeQuestionModel ??= new();
}
private async Task AddQuestion()
{
if (addQuestionModel?.Text is not string text)
{
return;
}
var question = new Question { Id = Guid.CreateVersion7(timeProvider.GetUtcNow()), Text = text };
questionnaireContext.Questions.Add(question);
await questionnaireContext.SaveChangesAsync();
}
private async Task RemoveQuestion()
{
if (removeQuestionModel?.QuestionId is not string questionId || !Guid.TryParse(questionId, out var id))
{
return;
}
var question = questionnaireContext.Questions.SingleOrDefault(q => q.Id == id);
if (question is null)
{
return;
}
questionnaireContext.Questions.Remove(question);
await questionnaireContext.SaveChangesAsync();
}
private sealed class AddQuestionModel
{
public string? Text { get; set; }
}
private sealed class RemoveQuestionModel
{
public string? QuestionId { get; set; }
}
}
MatDenDagen/Components/Pages/UploadTest.razor
+9
-3
diff --git a/MatDenDagen/Components/Pages/UploadTest.razor b/MatDenDagen/Components/Pages/UploadTest.razor
index 9aad47b..44656ef 100644
@@ -20,7 +20,8 @@
</p>
</EditForm>
@if (uploadedId is not null) {
@if (uploadedId is not null)
{
<p>Filen har id: <code>@uploadedId</code></p>
}
@@ -28,10 +29,15 @@
private readonly CancellationTokenSource cts = new();
[SupplyParameterFromForm]
private UploadTestModel? model { get; set; } = new();
private UploadTestModel? model { get; set; }
private string? uploadedId { get; set; }
protected override void OnInitialized()
{
model ??= new();
}
private async Task Submit()
{
if (model?.File is not { } file)
MatDenDagen/Infrastructure/Storage/Database/Migrations/20260502114950_InitialCreate.Designer.cs
+94
-0
diff --git a/MatDenDagen/Infrastructure/Storage/Database/Migrations/20260502114950_InitialCreate.Designer.cs b/MatDenDagen/Infrastructure/Storage/Database/Migrations/20260502114950_InitialCreate.Designer.cs
new file mode 100644
index 0000000..b4558b7
@@ -0,0 +1,94 @@
// <auto-generated />
using System;
using MatDenDagen.Infrastructure.Storage.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace MatDenDagen.Infrastructure.Storage.Database.Migrations
{
[DbContext(typeof(QuestionnaireContext))]
[Migration("20260502114950_InitialCreate")]
partial class InitialCreate
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "10.0.7");
modelBuilder.Entity("MatDenDagen.Models.Answer", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("QuestionId")
.HasColumnType("TEXT");
b.Property<Guid?>("SubmissionId")
.HasColumnType("TEXT");
b.Property<string>("Text")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("QuestionId");
b.HasIndex("SubmissionId");
b.ToTable("Answer");
});
modelBuilder.Entity("MatDenDagen.Models.Question", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<string>("Text")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Questions");
});
modelBuilder.Entity("MatDenDagen.Models.Submission", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Submissions");
});
modelBuilder.Entity("MatDenDagen.Models.Answer", b =>
{
b.HasOne("MatDenDagen.Models.Question", null)
.WithMany()
.HasForeignKey("QuestionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MatDenDagen.Models.Submission", null)
.WithMany("Answers")
.HasForeignKey("SubmissionId");
});
modelBuilder.Entity("MatDenDagen.Models.Submission", b =>
{
b.Navigation("Answers");
});
#pragma warning restore 612, 618
}
}
}
MatDenDagen/Infrastructure/Storage/Database/Migrations/20260502114950_InitialCreate.cs
+79
-0
diff --git a/MatDenDagen/Infrastructure/Storage/Database/Migrations/20260502114950_InitialCreate.cs b/MatDenDagen/Infrastructure/Storage/Database/Migrations/20260502114950_InitialCreate.cs
new file mode 100644
index 0000000..4cea02c
@@ -0,0 +1,79 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MatDenDagen.Infrastructure.Storage.Database.Migrations
{
/// <inheritdoc />
public partial class InitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Questions",
columns: table => new
{
Id = table.Column<Guid>(type: "TEXT", nullable: false),
Text = table.Column<string>(type: "TEXT", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_Questions", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "Submissions",
columns: table => new { Id = table.Column<Guid>(type: "TEXT", nullable: false) },
constraints: table =>
{
table.PrimaryKey("PK_Submissions", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "Answer",
columns: table => new
{
Id = table.Column<Guid>(type: "TEXT", nullable: false),
QuestionId = table.Column<Guid>(type: "TEXT", nullable: false),
Text = table.Column<string>(type: "TEXT", nullable: false),
SubmissionId = table.Column<Guid>(type: "TEXT", nullable: true),
},
constraints: table =>
{
table.PrimaryKey("PK_Answer", x => x.Id);
table.ForeignKey(
name: "FK_Answer_Questions_QuestionId",
column: x => x.QuestionId,
principalTable: "Questions",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
table.ForeignKey(
name: "FK_Answer_Submissions_SubmissionId",
column: x => x.SubmissionId,
principalTable: "Submissions",
principalColumn: "Id"
);
}
);
migrationBuilder.CreateIndex(name: "IX_Answer_QuestionId", table: "Answer", column: "QuestionId");
migrationBuilder.CreateIndex(name: "IX_Answer_SubmissionId", table: "Answer", column: "SubmissionId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "Answer");
migrationBuilder.DropTable(name: "Questions");
migrationBuilder.DropTable(name: "Submissions");
}
}
}
MatDenDagen/Infrastructure/Storage/Database/Migrations/QuestionnaireContextModelSnapshot.cs
+91
-0
diff --git a/MatDenDagen/Infrastructure/Storage/Database/Migrations/QuestionnaireContextModelSnapshot.cs b/MatDenDagen/Infrastructure/Storage/Database/Migrations/QuestionnaireContextModelSnapshot.cs
new file mode 100644
index 0000000..0b5835c
@@ -0,0 +1,91 @@
// <auto-generated />
using System;
using MatDenDagen.Infrastructure.Storage.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace MatDenDagen.Infrastructure.Storage.Database.Migrations
{
[DbContext(typeof(QuestionnaireContext))]
partial class QuestionnaireContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "10.0.7");
modelBuilder.Entity("MatDenDagen.Models.Answer", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("QuestionId")
.HasColumnType("TEXT");
b.Property<Guid?>("SubmissionId")
.HasColumnType("TEXT");
b.Property<string>("Text")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("QuestionId");
b.HasIndex("SubmissionId");
b.ToTable("Answer");
});
modelBuilder.Entity("MatDenDagen.Models.Question", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<string>("Text")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Questions");
});
modelBuilder.Entity("MatDenDagen.Models.Submission", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Submissions");
});
modelBuilder.Entity("MatDenDagen.Models.Answer", b =>
{
b.HasOne("MatDenDagen.Models.Question", null)
.WithMany()
.HasForeignKey("QuestionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MatDenDagen.Models.Submission", null)
.WithMany("Answers")
.HasForeignKey("SubmissionId");
});
modelBuilder.Entity("MatDenDagen.Models.Submission", b =>
{
b.Navigation("Answers");
});
#pragma warning restore 612, 618
}
}
}
MatDenDagen/Infrastructure/Storage/Database/QuestionnaireContext.cs
+26
-0
diff --git a/MatDenDagen/Infrastructure/Storage/Database/QuestionnaireContext.cs b/MatDenDagen/Infrastructure/Storage/Database/QuestionnaireContext.cs
new file mode 100644
index 0000000..37f11a7
@@ -0,0 +1,26 @@
using MatDenDagen.Models;
using Microsoft.EntityFrameworkCore;
namespace MatDenDagen.Infrastructure.Storage.Database;
public sealed class QuestionnaireContext(DbContextOptions<QuestionnaireContext> options) : DbContext(options)
{
public required DbSet<Question> Questions { get; init; }
public required DbSet<Submission> Submissions { get; init; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var questionBuilder = modelBuilder.Entity<Question>();
questionBuilder.HasKey(q => q.Id);
questionBuilder.Property(q => q.Text);
var submissionBuilder = modelBuilder.Entity<Submission>();
submissionBuilder.HasKey(s => s.Id);
submissionBuilder.HasMany(s => s.Answers).WithOne();
var answerBuilder = modelBuilder.Entity<Answer>();
answerBuilder.HasKey(a => a.Id);
answerBuilder.Property(a => a.Text);
answerBuilder.HasOne<Question>().WithMany().HasForeignKey(a => a.QuestionId);
}
}
MatDenDagen/Infrastructure/Storage/Database/StartupMigration.cs
+19
-0
diff --git a/MatDenDagen/Infrastructure/Storage/Database/StartupMigration.cs b/MatDenDagen/Infrastructure/Storage/Database/StartupMigration.cs
new file mode 100644
index 0000000..9e8ace5
@@ -0,0 +1,19 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace MatDenDagen.Infrastructure.Storage.Database;
public class StartupMigration(IServiceScopeFactory scopeFactory) : IHostedService
{
public async Task StartAsync(CancellationToken cancellationToken)
{
using var scope = scopeFactory.CreateScope();
var questionnaireContext = scope.ServiceProvider.GetRequiredService<QuestionnaireContext>();
await questionnaireContext.Database.MigrateAsync(cancellationToken);
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
MatDenDagen/Infrastructure/Storage/StorageServiceExtensions.cs
+8
-0
diff --git a/MatDenDagen/Infrastructure/Storage/StorageServiceExtensions.cs b/MatDenDagen/Infrastructure/Storage/StorageServiceExtensions.cs
index 7c84cc0..55079bc 100644
@@ -1,5 +1,8 @@
using System;
using MatDenDagen.Infrastructure.Storage.BlobStorage;
using MatDenDagen.Infrastructure.Storage.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
@@ -13,6 +16,11 @@ public static class StorageServiceExtensions
services.AddBlobStorageOptions().AddTransient<BlobStorageService>();
services.AddDbContext<QuestionnaireContext>(
(sp, options) => options.UseSqlite(sp.GetRequiredService<IConfiguration>().GetConnectionString("database"))
);
services.AddHostedService<StartupMigration>();
return services;
}
}
MatDenDagen/MatDenDagen.csproj
+6
-0
diff --git a/MatDenDagen/MatDenDagen.csproj b/MatDenDagen/MatDenDagen.csproj
index 6d47627..ec4381b 100644
@@ -5,9 +5,15 @@
<RequiresAspNetWebAssets>true</RequiresAspNetWebAssets>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
<PackageReference Include="OpenTelemetry.Instrumentation.EntityFrameworkCore" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" />
</ItemGroup>
MatDenDagen/Models/Answer.cs
+10
-0
diff --git a/MatDenDagen/Models/Answer.cs b/MatDenDagen/Models/Answer.cs
new file mode 100644
index 0000000..173f53a
@@ -0,0 +1,10 @@
using System;
namespace MatDenDagen.Models;
public sealed class Answer
{
public required Guid Id { get; init; }
public required Guid QuestionId { get; init; }
public required string Text { get; init; }
}
MatDenDagen/Models/Question.cs
+9
-0
diff --git a/MatDenDagen/Models/Question.cs b/MatDenDagen/Models/Question.cs
new file mode 100644
index 0000000..4a87dc6
@@ -0,0 +1,9 @@
using System;
namespace MatDenDagen.Models;
public sealed class Question
{
public required Guid Id { get; init; }
public required string Text { get; init; }
}
MatDenDagen/Models/Submission.cs
+9
-0
diff --git a/MatDenDagen/Models/Submission.cs b/MatDenDagen/Models/Submission.cs
new file mode 100644
index 0000000..1845e90
@@ -0,0 +1,9 @@
using System;
namespace MatDenDagen.Models;
public sealed class Submission
{
public required Guid Id { get; init; }
public required Answer[] Answers { get; init; }
}
MatDenDagen/OpenTelemetryExtensions.cs
+1
-0
diff --git a/MatDenDagen/OpenTelemetryExtensions.cs b/MatDenDagen/OpenTelemetryExtensions.cs
index 7602209..3232cb1 100644
@@ -30,6 +30,7 @@ public static class OpenTelemetryExtensions
.AddSource(builder.Environment.ApplicationName)
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddEntityFrameworkCoreInstrumentation()
.AddSource(nameof(MatDenDagen));
});
MatDenDagen/appsettings.Development.json
+3
-0
diff --git a/MatDenDagen/appsettings.Development.json b/MatDenDagen/appsettings.Development.json
index 07d40da..cf9e8b4 100644
@@ -6,6 +6,9 @@
"MatDenDagen": "Debug"
}
},
"ConnectionStrings": {
"database": "Data Source=../database.db"
},
"Storage": {
"BlobDirectory": "../blobs"
}
MatDenDagen/packages.lock.json
+299
-6
diff --git a/MatDenDagen/packages.lock.json b/MatDenDagen/packages.lock.json
index 7d8ba14..7b95fa1 100644
@@ -14,6 +14,35 @@
"resolved": "10.0.7",
"contentHash": "ao3i+ks0uOQ7FWacI1hqHkUczebmXrGkUB63Xhkc34QbSzG9nYBlDv9v5l6rtCrHMsDW+13kZlpJrSj1HXddqg=="
},
"Microsoft.EntityFrameworkCore.Design": {
"type": "Direct",
"requested": "[10.0.7, )",
"resolved": "10.0.7",
"contentHash": "8UMWkJdfwN/tyEZS6zd0s55zE5zaG4owldh+E91vXitHmux3FTP6Hjhgk6RL9Sv+TdO4FMERQIT6VzBtRrb1AQ==",
"dependencies": {
"Humanizer.Core": "2.14.1",
"Microsoft.Build.Framework": "18.0.2",
"Microsoft.CodeAnalysis.CSharp": "5.0.0",
"Microsoft.CodeAnalysis.CSharp.Workspaces": "5.0.0",
"Microsoft.CodeAnalysis.Workspaces.MSBuild": "5.0.0",
"Microsoft.EntityFrameworkCore.Relational": "10.0.7",
"Microsoft.Extensions.DependencyModel": "10.0.7",
"Mono.TextTemplating": "3.0.0",
"Newtonsoft.Json": "13.0.3"
}
},
"Microsoft.EntityFrameworkCore.Sqlite": {
"type": "Direct",
"requested": "[10.0.7, )",
"resolved": "10.0.7",
"contentHash": "0cnk9Chkuz2Jc6pbXRqdjy2CMAi62q4dJhvJzG25iCIvbavUYLxk/5ukwM+mzOl7ADN88WPmY1Lx1cAH2g8QSA==",
"dependencies": {
"Microsoft.EntityFrameworkCore.Sqlite.Core": "10.0.7",
"Microsoft.Extensions.DependencyModel": "10.0.7",
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.11",
"SQLitePCLRaw.core": "2.1.11"
}
},
"OpenTelemetry.Exporter.OpenTelemetryProtocol": {
"type": "Direct",
"requested": "[1.15.3, )",
@@ -41,6 +70,15 @@
"OpenTelemetry.Api.ProviderBuilderExtensions": "[1.15.3, 2.0.0)"
}
},
"OpenTelemetry.Instrumentation.EntityFrameworkCore": {
"type": "Direct",
"requested": "[1.15.1-beta.1, )",
"resolved": "1.15.1-beta.1",
"contentHash": "NmtYLk3HJUUkV0g2VnFLs67/PGIVbI8JXtu0g4f9bk2ZaInp211/AL2+Qcbgkb9ih/uOi8loN6E1Aw2o0YIWag==",
"dependencies": {
"OpenTelemetry.Api.ProviderBuilderExtensions": "[1.15.3, 2.0.0)"
}
},
"OpenTelemetry.Instrumentation.Http": {
"type": "Direct",
"requested": "[1.15.1, )",
@@ -59,6 +97,145 @@
"OpenTelemetry.Api": "[1.15.3, 2.0.0)"
}
},
"Humanizer.Core": {
"type": "Transitive",
"resolved": "2.14.1",
"contentHash": "lQKvtaTDOXnoVJ20ibTuSIOf2i0uO0MPbDhd1jm238I+U/2ZnRENj0cktKZhtchBMtCUSRQ5v4xBCUbKNmyVMw=="
},
"Microsoft.Build.Framework": {
"type": "Transitive",
"resolved": "18.0.2",
"contentHash": "sOSb+0J4G/jCBW/YqmRuL0eOMXgfw1KQLdC9TkbvfA5xs7uNm+PBQXJCOzSJGXtZcZrtXozcwxPmUiRUbmd7FA=="
},
"Microsoft.CodeAnalysis.Analyzers": {
"type": "Transitive",
"resolved": "3.11.0",
"contentHash": "v/EW3UE8/lbEYHoC2Qq7AR/DnmvpgdtAMndfQNmpuIMx/Mto8L5JnuCfdBYtgvalQOtfNCnxFejxuRrryvUTsg=="
},
"Microsoft.CodeAnalysis.Common": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "ZXRAdvH6GiDeHRyd3q/km8Z44RoM6FBWHd+gen/la81mVnAdHTEsEkO5J0TCNXBymAcx5UYKt5TvgKBhaLJEow==",
"dependencies": {
"Microsoft.CodeAnalysis.Analyzers": "3.11.0"
}
},
"Microsoft.CodeAnalysis.CSharp": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "5DSyJ9bk+ATuDy7fp2Zt0mJStDVKbBoiz1DyfAwSa+k4H4IwykAUcV3URelw5b8/iVbfSaOwkwmPUZH6opZKCw==",
"dependencies": {
"Microsoft.CodeAnalysis.Analyzers": "3.11.0",
"Microsoft.CodeAnalysis.Common": "[5.0.0]"
}
},
"Microsoft.CodeAnalysis.CSharp.Workspaces": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "Al/Q8B+yO8odSqGVpSvrShMFDvlQdIBU//F3E6Rb0YdiLSALE9wh/pvozPNnfmh5HDnvU+mkmSjpz4hQO++jaA==",
"dependencies": {
"Humanizer.Core": "2.14.1",
"Microsoft.CodeAnalysis.Analyzers": "3.11.0",
"Microsoft.CodeAnalysis.CSharp": "[5.0.0]",
"Microsoft.CodeAnalysis.Common": "[5.0.0]",
"Microsoft.CodeAnalysis.Workspaces.Common": "[5.0.0]",
"System.Composition": "9.0.0"
}
},
"Microsoft.CodeAnalysis.Workspaces.Common": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "ZbUmIvT6lqTNKiv06Jl5wf0MTMi1vQ1oH7ou4CLcs2C/no/L7EhP3T8y3XXvn9VbqMcJaJnEsNA1jwYUMgc5jg==",
"dependencies": {
"Humanizer.Core": "2.14.1",
"Microsoft.CodeAnalysis.Analyzers": "3.11.0",
"Microsoft.CodeAnalysis.Common": "[5.0.0]",
"System.Composition": "9.0.0"
}
},
"Microsoft.CodeAnalysis.Workspaces.MSBuild": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "/G+LVoAGMz6Ae8nm+PGLxSw+F5RjYx/J7irbTO5uKAPw1bxHyQJLc/YOnpDxt+EpPtYxvC9wvBsg/kETZp1F9Q==",
"dependencies": {
"Humanizer.Core": "2.14.1",
"Microsoft.Build.Framework": "17.11.31",
"Microsoft.CodeAnalysis.Analyzers": "3.11.0",
"Microsoft.CodeAnalysis.Workspaces.Common": "[5.0.0]",
"Microsoft.VisualStudio.SolutionPersistence": "1.0.52",
"Newtonsoft.Json": "13.0.3",
"System.Composition": "9.0.0"
}
},
"Microsoft.Data.Sqlite.Core": {
"type": "Transitive",
"resolved": "10.0.7",
"contentHash": "xVrtBg3M1wJlBDkoT0dXEYB/wSc8bIHJPYtw/bu1AqpWgF79uPSs87DAhERR/Ilumre6TKZa1cjMg3VUUObVLA==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.11"
}
},
"Microsoft.EntityFrameworkCore": {
"type": "Transitive",
"resolved": "10.0.7",
"contentHash": "G6yclVO5/csPzzsymV0SemY2NDqE31CP5M3jprF5IuO9wJsh4aUOfYD8HCLuDmM1D1CfReegVic48O2r79d46Q==",
"dependencies": {
"Microsoft.EntityFrameworkCore.Abstractions": "10.0.7",
"Microsoft.EntityFrameworkCore.Analyzers": "10.0.7"
}
},
"Microsoft.EntityFrameworkCore.Abstractions": {
"type": "Transitive",
"resolved": "10.0.7",
"contentHash": "TuxExnfIS/bSq3z2CbH0LwZH1oyj9iHhSGneU4fpxl3ikjZGZdSae9gcfnImV1rufH8f/ab1NnHwyL2BLyeZOg=="
},
"Microsoft.EntityFrameworkCore.Analyzers": {
"type": "Transitive",
"resolved": "10.0.7",
"contentHash": "eZnMyiJzo249Ejg5CaFScvJS0u7neQfS9DXknAHTO6FHVMM99gO0byNXHGZmA/BOkZ13ngeVziQLHTMOtgescg=="
},
"Microsoft.EntityFrameworkCore.Relational": {
"type": "Transitive",
"resolved": "10.0.7",
"contentHash": "midwPufIwXhOJcVhaZpCZGNbjy2QoPfHI+70nw2dGcoULEW9DybMvMPYkRjOJV0eI46a1oVFhU4lFYDEx6YUbg==",
"dependencies": {
"Microsoft.EntityFrameworkCore": "10.0.7"
}
},
"Microsoft.EntityFrameworkCore.Sqlite.Core": {
"type": "Transitive",
"resolved": "10.0.7",
"contentHash": "XVjGSW98Z/f3nFZsZILL/tntgM8i2hxUDUB4Nzt7ZvJ63MczC/VG4zjQh+m+q88SU+IJBUDipJJpkYBU57YWXg==",
"dependencies": {
"Microsoft.Data.Sqlite.Core": "10.0.7",
"Microsoft.EntityFrameworkCore.Relational": "10.0.7",
"Microsoft.Extensions.DependencyModel": "10.0.7",
"SQLitePCLRaw.core": "2.1.11"
}
},
"Microsoft.Extensions.DependencyModel": {
"type": "Transitive",
"resolved": "10.0.7",
"contentHash": "gCglFg/9Chu3lyJNytRuQAYM3mXQKNs1i01Cz2bc545QaHQ+LbBb4O5UCfu968Gro3ZVSOZ/ktilmPcaUSGSZA=="
},
"Microsoft.VisualStudio.SolutionPersistence": {
"type": "Transitive",
"resolved": "1.0.52",
"contentHash": "oNv2JtYXhpdJrX63nibx1JT3uCESOBQ1LAk7Dtz/sr0+laW0KRM6eKp4CZ3MHDR2siIkKsY8MmUkeP5DKkQQ5w=="
},
"Mono.TextTemplating": {
"type": "Transitive",
"resolved": "3.0.0",
"contentHash": "YqueG52R/Xej4VVbKuRIodjiAhV0HR/XVbLbNrJhCZnzjnSjgMJ/dCdV0akQQxavX6hp/LC6rqLGLcXeQYU7XA==",
"dependencies": {
"System.CodeDom": "6.0.0"
}
},
"Newtonsoft.Json": {
"type": "Transitive",
"resolved": "13.0.3",
"contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
},
"OpenTelemetry": {
"type": "Transitive",
"resolved": "1.15.3",
@@ -79,13 +256,129 @@
"dependencies": {
"OpenTelemetry.Api": "1.15.3"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.11",
"contentHash": "DC4nA7yWnf4UZdgJDF+9Mus4/cb0Y3Sfgi3gDnAoKNAIBwzkskNAbNbyu+u4atT0ruVlZNJfwZmwiEwE5oz9LQ==",
"dependencies": {
"SQLitePCLRaw.lib.e_sqlite3": "2.1.11",
"SQLitePCLRaw.provider.e_sqlite3": "2.1.11"
}
},
"SQLitePCLRaw.core": {
"type": "Transitive",
"resolved": "2.1.11",
"contentHash": "PK0GLFkfhZzLQeR3PJf71FmhtHox+U3vcY6ZtswoMjrefkB9k6ErNJEnwXqc5KgXDSjige2XXrezqS39gkpQKA=="
},
"SQLitePCLRaw.lib.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.11",
"contentHash": "Ev2ytaXiOlWZ4b3R67GZBsemTINslLD1DCJr2xiacpn4tbapu0Q4dHEzSvZSMnVWeE5nlObU3VZN2p81q3XOYQ=="
},
"SQLitePCLRaw.provider.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.11",
"contentHash": "Y/0ZkR+r0Cg3DQFuCl1RBnv/tmxpIZRU3HUvelPw6MVaKHwYYR8YNvgs0vuNuXCMvlyJ+Fh88U1D4tah1tt6qw==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.11"
}
},
"System.CodeDom": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "CPc6tWO1LAer3IzfZufDBRL+UZQcj5uS207NHALQzP84Vp/z6wF0Aa0YZImOQY8iStY0A2zI/e3ihKNPfUm8XA=="
},
"System.Composition": {
"type": "Transitive",
"resolved": "9.0.0",
"contentHash": "3Djj70fFTraOarSKmRnmRy/zm4YurICm+kiCtI0dYRqGJnLX6nJ+G3WYuFJ173cAPax/gh96REcbNiVqcrypFQ==",
"dependencies": {
"System.Composition.AttributedModel": "9.0.0",
"System.Composition.Convention": "9.0.0",
"System.Composition.Hosting": "9.0.0",
"System.Composition.Runtime": "9.0.0",
"System.Composition.TypedParts": "9.0.0"
}
},
"System.Composition.AttributedModel": {
"type": "Transitive",
"resolved": "9.0.0",
"contentHash": "iri00l/zIX9g4lHMY+Nz0qV1n40+jFYAmgsaiNn16xvt2RDwlqByNG4wgblagnDYxm3YSQQ0jLlC/7Xlk9CzyA=="
},
"System.Composition.Convention": {
"type": "Transitive",
"resolved": "9.0.0",
"contentHash": "+vuqVP6xpi582XIjJi6OCsIxuoTZfR0M7WWufk3uGDeCl3wGW6KnpylUJ3iiXdPByPE0vR5TjJgR6hDLez4FQg==",
"dependencies": {
"System.Composition.AttributedModel": "9.0.0"
}
},
"System.Composition.Hosting": {
"type": "Transitive",
"resolved": "9.0.0",
"contentHash": "OFqSeFeJYr7kHxDfaViGM1ymk7d4JxK//VSoNF9Ux0gpqkLsauDZpu89kTHHNdCWfSljbFcvAafGyBoY094btQ==",
"dependencies": {
"System.Composition.Runtime": "9.0.0"
}
},
"System.Composition.Runtime": {
"type": "Transitive",
"resolved": "9.0.0",
"contentHash": "w1HOlQY1zsOWYussjFGZCEYF2UZXgvoYnS94NIu2CBnAGMbXFAX8PY8c92KwUItPmowal68jnVLBCzdrWLeEKA=="
},
"System.Composition.TypedParts": {
"type": "Transitive",
"resolved": "9.0.0",
"contentHash": "aRZlojCCGEHDKqh43jaDgaVpYETsgd7Nx4g1zwLKMtv4iTo0627715ajEFNpEEBTgLmvZuv8K0EVxc3sM4NWJA==",
"dependencies": {
"System.Composition.AttributedModel": "9.0.0",
"System.Composition.Hosting": "9.0.0",
"System.Composition.Runtime": "9.0.0"
}
}
},
"net10.0/linux-arm64": {
"SQLitePCLRaw.lib.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.11",
"contentHash": "Ev2ytaXiOlWZ4b3R67GZBsemTINslLD1DCJr2xiacpn4tbapu0Q4dHEzSvZSMnVWeE5nlObU3VZN2p81q3XOYQ=="
}
},
"net10.0/linux-x64": {
"SQLitePCLRaw.lib.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.11",
"contentHash": "Ev2ytaXiOlWZ4b3R67GZBsemTINslLD1DCJr2xiacpn4tbapu0Q4dHEzSvZSMnVWeE5nlObU3VZN2p81q3XOYQ=="
}
},
"net10.0/osx-arm64": {
"SQLitePCLRaw.lib.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.11",
"contentHash": "Ev2ytaXiOlWZ4b3R67GZBsemTINslLD1DCJr2xiacpn4tbapu0Q4dHEzSvZSMnVWeE5nlObU3VZN2p81q3XOYQ=="
}
},
"net10.0/linux-arm64": {},
"net10.0/linux-x64": {},
"net10.0/osx-arm64": {},
"net10.0/osx-x64": {},
"net10.0/win-arm64": {},
"net10.0/win-x64": {}
"net10.0/osx-x64": {
"SQLitePCLRaw.lib.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.11",
"contentHash": "Ev2ytaXiOlWZ4b3R67GZBsemTINslLD1DCJr2xiacpn4tbapu0Q4dHEzSvZSMnVWeE5nlObU3VZN2p81q3XOYQ=="
}
},
"net10.0/win-arm64": {
"SQLitePCLRaw.lib.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.11",
"contentHash": "Ev2ytaXiOlWZ4b3R67GZBsemTINslLD1DCJr2xiacpn4tbapu0Q4dHEzSvZSMnVWeE5nlObU3VZN2p81q3XOYQ=="
}
},
"net10.0/win-x64": {
"SQLitePCLRaw.lib.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.11",
"contentHash": "Ev2ytaXiOlWZ4b3R67GZBsemTINslLD1DCJr2xiacpn4tbapu0Q4dHEzSvZSMnVWeE5nlObU3VZN2p81q3XOYQ=="
}
}
}
}
\ No newline at end of file
README.md
+2
-1
diff --git a/README.md b/README.md
index 917e2c5..5e65571 100644
@@ -11,8 +11,9 @@
- [ ] Configure participants
- [ ] Phone number for notifications
- [ ] Time of day the want to be notified
- [x] Configure questions
- [ ] Export answers
- [ ] Internals
- [ ] Job that sends out notifications
- [ ] Storage for text answers
- [x] Storage for text answers
- [x] Storage for photo (video?) uploads
dotnet-tools.json
+7
-0
diff --git a/dotnet-tools.json b/dotnet-tools.json
index 97f37dc..3471b9c 100644
@@ -8,6 +8,13 @@
"csharpier"
],
"rollForward": false
},
"dotnet-ef": {
"version": "10.0.7",
"commands": [
"dotnet-ef"
],
"rollForward": false
}
}
}
\ No newline at end of file