tiny server.

This commit is contained in:
2023-05-23 08:37:20 +08:00
parent 78a5d8d3fa
commit c8bf017a70
50 changed files with 1242 additions and 32 deletions

View File

@ -0,0 +1,12 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "7.0.5",
"commands": [
"dotnet-ef"
]
}
}
}

View File

@ -0,0 +1,60 @@
using Blahblah.FlowerStory.Server.Data;
using Blahblah.FlowerStory.Server.Data.Model;
using Microsoft.AspNetCore.Mvc;
namespace Blahblah.FlowerStory.Server.Controller
{
[ApiController]
[Route("users")]
public class UserController : ControllerBase
{
private readonly FlowerDatabase database;
private readonly ILogger<UserController> logger;
public UserController(FlowerDatabase db, ILogger<UserController> logger)
{
database = db;
this.logger = logger;
}
[Route("query")]
[HttpGet]
public ActionResult<UserItem[]> GetUsers()
{
//var forecast = Enumerable.Range(1, 5).Select(index =>
// new WeatherForecast
// {
// Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
// TemperatureC = Random.Shared.Next(-20, 55),
// Summary = summaries[Random.Shared.Next(summaries.Length)]
// })
// .ToArray();
//return Ok(forecast);
return Ok(database.Users.ToArray());
}
[Route("update")]
[HttpPost]
public ActionResult<int> UpdateUser([FromBody] UserItem item)
{
if (item.Id > 0)
{
database.Update(item);
}
else
{
database.Add(item);
}
var count = database.SaveChanges();
if (count > 0)
{
logger.LogInformation("{number} of entries written to database.", count);
}
else
{
logger.LogWarning("no data written to database.");
}
return Ok(item.Id);
}
}
}

View File

@ -0,0 +1,15 @@
using Blahblah.FlowerStory.Server.Data.Model;
using Microsoft.EntityFrameworkCore;
namespace Blahblah.FlowerStory.Server.Data;
public class FlowerDatabase : DbContext
{
public FlowerDatabase(DbContextOptions<FlowerDatabase> options) : base(options) { }
public DbSet<UserItem> Users { get; set; }
public DbSet<FlowerItem> Flowers { get; set; }
public DbSet<RecordItem> Records { get; set; }
}

View File

@ -0,0 +1,32 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Blahblah.FlowerStory.Server.Data.Model;
[Table("flowers")]
public class FlowerItem
{
[Column("fid"), Key, Required]
public int Id { get; set; }
[Column("categoryid"), Required]
public int CategoryId { get; set; }
[Column("name"), Required]
public required string Name { get; set; }
[Column("datebuy"), Required]
public long DateBuyUnixTime { get; set; }
[Column("cost", TypeName = "real")]
public decimal? Cost { get; set; }
[Column("purchase")]
public string? Purchase { get; set; }
[Column("photo")]
public byte[]? Photo { get; set; }
[NotMapped]
public DateTimeOffset DateBuy => DateTimeOffset.FromUnixTimeMilliseconds(DateBuyUnixTime);
}

View File

@ -0,0 +1,29 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Blahblah.FlowerStory.Server.Data.Model;
[Table("records")]
public class RecordItem
{
[Column("rid"), Key, Required]
public int Id { get; set; }
[Column("eid"), Required]
public int EventId { get; set; }
[Column("date"), Required]
public long DateUnixTime { get; set; }
[Column("byuid")]
public int? ByUserId { get; set; }
[Column("byname")]
public string? ByUserName { get; set; }
[Column("photo")]
public byte[]? Photo { get; set; }
[NotMapped]
public DateTimeOffset Date => DateTimeOffset.FromUnixTimeMilliseconds(DateUnixTime);
}

View File

@ -0,0 +1,32 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Blahblah.FlowerStory.Server.Data.Model;
[Table("users")]
public class UserItem
{
[Column("uid"), Key, Required]
public int Id { get; set; }
[Column("id"), Required]
public required string UserId { get; set; }
[Column("password"), Required]
public required string Password { get; set; }
[Column("level"), Required]
public int Level { get; set; }
[Column("regdate"), Required]
public long RegisterDateUnixTime { get; set; }
[Column("activedate")]
public long? ActiveDateUnixTime { get; set; }
[Column("name"), Required]
public required string Name { get; set; }
[Column("email")]
public string? Email { get; set; }
[Column("mobile")]
public string? Mobile { get; set; }
[NotMapped]
public DateTimeOffset RegisterDate => DateTimeOffset.FromUnixTimeMilliseconds(RegisterDateUnixTime);
[NotMapped]
public DateTimeOffset? ActiveDate => ActiveDateUnixTime == null ? null : DateTimeOffset.FromUnixTimeMilliseconds(ActiveDateUnixTime.Value);
}

View File

@ -0,0 +1,141 @@
// <auto-generated />
using System;
using Blahblah.FlowerStory.Server.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Blahblah.FlowerStory.Server.Migrations
{
[DbContext(typeof(FlowerDatabase))]
[Migration("20230522090224_InitialCreateDb")]
partial class InitialCreateDb
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "7.0.5");
modelBuilder.Entity("Blahblah.FlowerStory.Server.Data.Model.FlowerItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("fid");
b.Property<int>("CategoryId")
.HasColumnType("INTEGER")
.HasColumnName("categoryid");
b.Property<decimal?>("Cost")
.HasColumnType("real")
.HasColumnName("cost");
b.Property<DateTimeOffset>("DateBuy")
.HasColumnType("numeric")
.HasColumnName("datebuy");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("name");
b.Property<byte[]>("Photo")
.HasColumnType("BLOB")
.HasColumnName("photo");
b.Property<string>("Purchase")
.HasColumnType("TEXT")
.HasColumnName("purchase");
b.HasKey("Id");
b.ToTable("flowers");
});
modelBuilder.Entity("Blahblah.FlowerStory.Server.Data.Model.RecordItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("rid");
b.Property<int?>("ByUserId")
.HasColumnType("INTEGER")
.HasColumnName("byuid");
b.Property<string>("ByUserName")
.HasColumnType("TEXT")
.HasColumnName("byname");
b.Property<DateTimeOffset>("Date")
.HasColumnType("numeric")
.HasColumnName("date");
b.Property<int>("EventId")
.HasColumnType("INTEGER")
.HasColumnName("eid");
b.Property<byte[]>("Photo")
.HasColumnType("BLOB")
.HasColumnName("photo");
b.HasKey("Id");
b.ToTable("records");
});
modelBuilder.Entity("Blahblah.FlowerStory.Server.Data.Model.UserItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("uid");
b.Property<DateTimeOffset?>("ActiveDate")
.HasColumnType("numeric")
.HasColumnName("activedate");
b.Property<string>("Email")
.HasColumnType("TEXT")
.HasColumnName("email");
b.Property<int>("Level")
.HasColumnType("INTEGER")
.HasColumnName("level");
b.Property<string>("Mobile")
.HasColumnType("TEXT")
.HasColumnName("mobile");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("name");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("password");
b.Property<DateTimeOffset>("RegisterDate")
.HasColumnType("numeric")
.HasColumnName("regdate");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("id");
b.HasKey("Id");
b.ToTable("users");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,83 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Blahblah.FlowerStory.Server.Migrations
{
/// <inheritdoc />
public partial class InitialCreateDb : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "flowers",
columns: table => new
{
fid = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
categoryid = table.Column<int>(type: "INTEGER", nullable: false),
name = table.Column<string>(type: "TEXT", nullable: false),
datebuy = table.Column<DateTimeOffset>(type: "numeric", nullable: false),
cost = table.Column<decimal>(type: "real", nullable: true),
purchase = table.Column<string>(type: "TEXT", nullable: true),
photo = table.Column<byte[]>(type: "BLOB", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_flowers", x => x.fid);
});
migrationBuilder.CreateTable(
name: "records",
columns: table => new
{
rid = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
eid = table.Column<int>(type: "INTEGER", nullable: false),
date = table.Column<DateTimeOffset>(type: "numeric", nullable: false),
byuid = table.Column<int>(type: "INTEGER", nullable: true),
byname = table.Column<string>(type: "TEXT", nullable: true),
photo = table.Column<byte[]>(type: "BLOB", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_records", x => x.rid);
});
migrationBuilder.CreateTable(
name: "users",
columns: table => new
{
uid = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
id = table.Column<string>(type: "TEXT", nullable: false),
password = table.Column<string>(type: "TEXT", nullable: false),
level = table.Column<int>(type: "INTEGER", nullable: false),
regdate = table.Column<DateTimeOffset>(type: "numeric", nullable: false),
activedate = table.Column<DateTimeOffset>(type: "numeric", nullable: true),
name = table.Column<string>(type: "TEXT", nullable: false),
email = table.Column<string>(type: "TEXT", nullable: true),
mobile = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_users", x => x.uid);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "flowers");
migrationBuilder.DropTable(
name: "records");
migrationBuilder.DropTable(
name: "users");
}
}
}

View File

@ -0,0 +1,141 @@
// <auto-generated />
using System;
using Blahblah.FlowerStory.Server.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Blahblah.FlowerStory.Server.Migrations
{
[DbContext(typeof(FlowerDatabase))]
[Migration("20230522143925_ChangeDateColumnType")]
partial class ChangeDateColumnType
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "7.0.5");
modelBuilder.Entity("Blahblah.FlowerStory.Server.Data.Model.FlowerItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("fid");
b.Property<int>("CategoryId")
.HasColumnType("INTEGER")
.HasColumnName("categoryid");
b.Property<decimal?>("Cost")
.HasColumnType("real")
.HasColumnName("cost");
b.Property<long>("DateBuyUnixTime")
.HasColumnType("INTEGER")
.HasColumnName("datebuy");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("name");
b.Property<byte[]>("Photo")
.HasColumnType("BLOB")
.HasColumnName("photo");
b.Property<string>("Purchase")
.HasColumnType("TEXT")
.HasColumnName("purchase");
b.HasKey("Id");
b.ToTable("flowers");
});
modelBuilder.Entity("Blahblah.FlowerStory.Server.Data.Model.RecordItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("rid");
b.Property<int?>("ByUserId")
.HasColumnType("INTEGER")
.HasColumnName("byuid");
b.Property<string>("ByUserName")
.HasColumnType("TEXT")
.HasColumnName("byname");
b.Property<long>("DateUnixTime")
.HasColumnType("INTEGER")
.HasColumnName("date");
b.Property<int>("EventId")
.HasColumnType("INTEGER")
.HasColumnName("eid");
b.Property<byte[]>("Photo")
.HasColumnType("BLOB")
.HasColumnName("photo");
b.HasKey("Id");
b.ToTable("records");
});
modelBuilder.Entity("Blahblah.FlowerStory.Server.Data.Model.UserItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("uid");
b.Property<long?>("ActiveDateUnixTime")
.HasColumnType("INTEGER")
.HasColumnName("activedate");
b.Property<string>("Email")
.HasColumnType("TEXT")
.HasColumnName("email");
b.Property<int>("Level")
.HasColumnType("INTEGER")
.HasColumnName("level");
b.Property<string>("Mobile")
.HasColumnType("TEXT")
.HasColumnName("mobile");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("name");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("password");
b.Property<long>("RegisterDateUnixTime")
.HasColumnType("INTEGER")
.HasColumnName("regdate");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("id");
b.HasKey("Id");
b.ToTable("users");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,85 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Blahblah.FlowerStory.Server.Migrations
{
/// <inheritdoc />
public partial class ChangeDateColumnType : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<long>(
name: "regdate",
table: "users",
type: "INTEGER",
nullable: false,
oldClrType: typeof(DateTimeOffset),
oldType: "numeric");
migrationBuilder.AlterColumn<long>(
name: "activedate",
table: "users",
type: "INTEGER",
nullable: true,
oldClrType: typeof(DateTimeOffset),
oldType: "numeric",
oldNullable: true);
migrationBuilder.AlterColumn<long>(
name: "date",
table: "records",
type: "INTEGER",
nullable: false,
oldClrType: typeof(DateTimeOffset),
oldType: "numeric");
migrationBuilder.AlterColumn<long>(
name: "datebuy",
table: "flowers",
type: "INTEGER",
nullable: false,
oldClrType: typeof(DateTimeOffset),
oldType: "numeric");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<DateTimeOffset>(
name: "regdate",
table: "users",
type: "numeric",
nullable: false,
oldClrType: typeof(long),
oldType: "INTEGER");
migrationBuilder.AlterColumn<DateTimeOffset>(
name: "activedate",
table: "users",
type: "numeric",
nullable: true,
oldClrType: typeof(long),
oldType: "INTEGER",
oldNullable: true);
migrationBuilder.AlterColumn<DateTimeOffset>(
name: "date",
table: "records",
type: "numeric",
nullable: false,
oldClrType: typeof(long),
oldType: "INTEGER");
migrationBuilder.AlterColumn<DateTimeOffset>(
name: "datebuy",
table: "flowers",
type: "numeric",
nullable: false,
oldClrType: typeof(long),
oldType: "INTEGER");
}
}
}

View File

@ -0,0 +1,138 @@
// <auto-generated />
using System;
using Blahblah.FlowerStory.Server.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Blahblah.FlowerStory.Server.Migrations
{
[DbContext(typeof(FlowerDatabase))]
partial class FlowerDatabaseModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "7.0.5");
modelBuilder.Entity("Blahblah.FlowerStory.Server.Data.Model.FlowerItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("fid");
b.Property<int>("CategoryId")
.HasColumnType("INTEGER")
.HasColumnName("categoryid");
b.Property<decimal?>("Cost")
.HasColumnType("real")
.HasColumnName("cost");
b.Property<long>("DateBuyUnixTime")
.HasColumnType("INTEGER")
.HasColumnName("datebuy");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("name");
b.Property<byte[]>("Photo")
.HasColumnType("BLOB")
.HasColumnName("photo");
b.Property<string>("Purchase")
.HasColumnType("TEXT")
.HasColumnName("purchase");
b.HasKey("Id");
b.ToTable("flowers");
});
modelBuilder.Entity("Blahblah.FlowerStory.Server.Data.Model.RecordItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("rid");
b.Property<int?>("ByUserId")
.HasColumnType("INTEGER")
.HasColumnName("byuid");
b.Property<string>("ByUserName")
.HasColumnType("TEXT")
.HasColumnName("byname");
b.Property<long>("DateUnixTime")
.HasColumnType("INTEGER")
.HasColumnName("date");
b.Property<int>("EventId")
.HasColumnType("INTEGER")
.HasColumnName("eid");
b.Property<byte[]>("Photo")
.HasColumnType("BLOB")
.HasColumnName("photo");
b.HasKey("Id");
b.ToTable("records");
});
modelBuilder.Entity("Blahblah.FlowerStory.Server.Data.Model.UserItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("uid");
b.Property<long?>("ActiveDateUnixTime")
.HasColumnType("INTEGER")
.HasColumnName("activedate");
b.Property<string>("Email")
.HasColumnType("TEXT")
.HasColumnName("email");
b.Property<int>("Level")
.HasColumnType("INTEGER")
.HasColumnName("level");
b.Property<string>("Mobile")
.HasColumnType("TEXT")
.HasColumnName("mobile");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("name");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("password");
b.Property<long>("RegisterDateUnixTime")
.HasColumnType("INTEGER")
.HasColumnName("regdate");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("id");
b.HasKey("Id");
b.ToTable("users");
});
#pragma warning restore 612, 618
}
}
}

36
Server/Program.cs Normal file
View File

@ -0,0 +1,36 @@
using Blahblah.FlowerStory.Server.Controller;
using Blahblah.FlowerStory.Server.Data;
using Microsoft.EntityFrameworkCore;
namespace Blahblah.FlowerStory.Server;
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<FlowerDatabase>(options => options.UseSqlite("DataSource=flower.db;Cache=Shared"));
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAuthorization();
app.MapControllers();
app.Run();
}
}

View File

@ -0,0 +1,31 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:2132",
"sslPort": 0
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5247",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

27
Server/Server.csproj Normal file
View File

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>Blahblah.FlowerStory.Server</RootNamespace>
<UseAppHost>false</UseAppHost>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
<ItemGroup>
<None Update="flower.db">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

12
Server/WeatherForecast.cs Normal file
View File

@ -0,0 +1,12 @@
namespace Blahblah.FlowerStory.Server;
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

9
Server/appsettings.json Normal file
View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}