tiny server.
2
.gitignore
vendored
@ -4,6 +4,8 @@
|
|||||||
##
|
##
|
||||||
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||||
|
|
||||||
|
flower.db
|
||||||
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.rsuser
|
*.rsuser
|
||||||
*.suo
|
*.suo
|
||||||
|
62
App/Constants.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
namespace Blahblah.FlowerStory;
|
||||||
|
|
||||||
|
public sealed class Constants
|
||||||
|
{
|
||||||
|
public const string CategoryOther = "other";
|
||||||
|
public const string EventUnknown = "unknown";
|
||||||
|
|
||||||
|
public const SQLite.SQLiteOpenFlags Flags =
|
||||||
|
SQLite.SQLiteOpenFlags.ReadWrite |
|
||||||
|
SQLite.SQLiteOpenFlags.Create |
|
||||||
|
SQLite.SQLiteOpenFlags.SharedCache;
|
||||||
|
|
||||||
|
private const string databaseFilename = "flowerstory.db3";
|
||||||
|
public static string DatabasePath => Path.Combine(FileSystem.AppDataDirectory, databaseFilename);
|
||||||
|
|
||||||
|
public static readonly Dictionary<int, string> Categories = new()
|
||||||
|
{
|
||||||
|
[0] = CategoryOther,
|
||||||
|
[1] = "cactus", // 仙人球
|
||||||
|
[2] = "hibiscus", // 扶桑花
|
||||||
|
[3] = "bougainvillea", // 三角梅
|
||||||
|
[4] = "sunflower", // 太阳花
|
||||||
|
[5] = "milanflower", // 米兰花
|
||||||
|
[6] = "jasmine", // 茉莉花
|
||||||
|
[7] = "periwinkle", // 长春花
|
||||||
|
[8] = "nasturtium", // 旱金莲
|
||||||
|
[9] = "mirabilis", // 紫薇花
|
||||||
|
[10] = "tigerthornplum", // 虎刺梅
|
||||||
|
[11] = "geranium", // 天竺葵
|
||||||
|
[12] = "ballorchid", // 球兰
|
||||||
|
[13] = "medalchrysanthemum", // 勋章菊
|
||||||
|
[14] = "dianthus", // 石竹
|
||||||
|
[15] = "fivecolorplum", // 五色梅
|
||||||
|
[16] = "fuchsia", // 倒挂金钟
|
||||||
|
[17] = "bamboocrabapple", // 竹节海棠
|
||||||
|
[18] = "impatiens", // 凤仙花
|
||||||
|
[19] = "beautysakura", // 美女樱
|
||||||
|
[20] = "petunias", // 矮牵牛
|
||||||
|
[21] = "desertrose", // 沙漠玫瑰
|
||||||
|
[22] = "trailingcampanula", // 蔓性风铃花
|
||||||
|
[23] = "chineserose", // 月季花
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly Dictionary<int, Event> Events = new()
|
||||||
|
{
|
||||||
|
[0] = new(EventUnknown),
|
||||||
|
[1] = new("buy", true), // 购买
|
||||||
|
[2] = new("born", true), // 出生
|
||||||
|
[3] = new("changebasin"), // 换盆
|
||||||
|
[4] = new("watering"), // 浇水
|
||||||
|
[5] = new("fertilize"), // 施肥
|
||||||
|
[6] = new("germination"), // 发芽
|
||||||
|
[7] = new("blossom"), // 开花
|
||||||
|
[8] = new("fallenleaves"), // 落叶
|
||||||
|
[9] = new("prune"), // 修剪
|
||||||
|
[10] = new("sick"), // 生病
|
||||||
|
[11] = new("death", true), // 死亡
|
||||||
|
[12] = new("sell", true), // 出售
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Event(string Name, bool Unique = false);
|
44
App/Data/FlowerDatabase.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using Blahblah.FlowerStory.Data.Model;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using SQLite;
|
||||||
|
|
||||||
|
namespace Blahblah.FlowerStory.Data;
|
||||||
|
|
||||||
|
public class FlowerDatabase
|
||||||
|
{
|
||||||
|
private SQLiteAsyncConnection database;
|
||||||
|
|
||||||
|
private readonly ILogger logger;
|
||||||
|
public FlowerDatabase(ILogger<FlowerDatabase> logger)
|
||||||
|
{
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Init()
|
||||||
|
{
|
||||||
|
if (database is not null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
database = new SQLiteAsyncConnection(Constants.DatabasePath, Constants.Flags);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
var result =
|
||||||
|
#endif
|
||||||
|
await database.CreateTablesAsync<FlowerItem, RecordItem>();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
foreach (var item in result.Results)
|
||||||
|
{
|
||||||
|
logger.LogDebug("create table {table}, result: {result}", item.Key, item.Value);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<FlowerItem>> GetFlowers()
|
||||||
|
{
|
||||||
|
await Init();
|
||||||
|
return await database.Table<FlowerItem>().ToListAsync();
|
||||||
|
}
|
||||||
|
}
|
45
App/Data/Model/FlowerItem.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using SQLite;
|
||||||
|
|
||||||
|
namespace Blahblah.FlowerStory.Data.Model;
|
||||||
|
|
||||||
|
[Table("flowers")]
|
||||||
|
public class FlowerItem
|
||||||
|
{
|
||||||
|
[Column("fid"), PrimaryKey, AutoIncrement]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[Column("categoryid")]
|
||||||
|
public int CategoryId { get; set; }
|
||||||
|
|
||||||
|
private string categoryName;
|
||||||
|
public string CategoryName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (categoryName == null)
|
||||||
|
{
|
||||||
|
if (!Constants.Categories.TryGetValue(CategoryId, out categoryName))
|
||||||
|
{
|
||||||
|
categoryName = Constants.CategoryOther;
|
||||||
|
}
|
||||||
|
// TODO: i18n
|
||||||
|
}
|
||||||
|
return categoryName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Column("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[Column("datebuy")]
|
||||||
|
public DateTimeOffset DateBuy { get; set; }
|
||||||
|
|
||||||
|
[Column("cost")]
|
||||||
|
public decimal? Cost { get; set; }
|
||||||
|
|
||||||
|
[Column("purchase")]
|
||||||
|
public string Purchase { get; set; }
|
||||||
|
|
||||||
|
[Column("photo")]
|
||||||
|
public byte[] Photo { get; set; }
|
||||||
|
}
|
46
App/Data/Model/RecordItem.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
using SQLite;
|
||||||
|
|
||||||
|
namespace Blahblah.FlowerStory.Data.Model;
|
||||||
|
|
||||||
|
[Table("records")]
|
||||||
|
public class RecordItem
|
||||||
|
{
|
||||||
|
[Column("rid"), PrimaryKey, AutoIncrement]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[Column("eid")]
|
||||||
|
public int EventId { get; set; }
|
||||||
|
|
||||||
|
private string eventName;
|
||||||
|
public string EventName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (eventName == null)
|
||||||
|
{
|
||||||
|
if (Constants.Events.TryGetValue(EventId, out var @event))
|
||||||
|
{
|
||||||
|
eventName = @event.Name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eventName = Constants.EventUnknown;
|
||||||
|
}
|
||||||
|
// TODO: i18n
|
||||||
|
}
|
||||||
|
return eventName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Column("date")]
|
||||||
|
public DateTimeOffset Date { get; set; }
|
||||||
|
|
||||||
|
[Column("byuid")]
|
||||||
|
public int? ByUserId { get; set; }
|
||||||
|
|
||||||
|
[Column("byname")]
|
||||||
|
public string ByUserName { get; set; }
|
||||||
|
|
||||||
|
[Column("photo")]
|
||||||
|
public byte[] Photo { get; set; }
|
||||||
|
}
|
11
App/Data/Model/UserItem.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace Blahblah.FlowerStory.Data.Model;
|
||||||
|
|
||||||
|
public class UserItem
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public int Level { get; set; }
|
||||||
|
public DateTimeOffset RegisterDate { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Email { get; set; }
|
||||||
|
public string Mobile { get; set; }
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net7.0-android;net7.0-ios</TargetFrameworks>
|
<TargetFrameworks>net7.0-android</TargetFrameworks>
|
||||||
|
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RootNamespace>Blahblah.FlowerStory</RootNamespace>
|
<RootNamespace>Blahblah.FlowerStory</RootNamespace>
|
||||||
@ -25,24 +25,26 @@
|
|||||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">23.0</SupportedOSPlatformVersion>
|
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">23.0</SupportedOSPlatformVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net7.0-android|AnyCPU'">
|
||||||
|
<RuntimeIdentifiers>android-x64</RuntimeIdentifiers>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net7.0-android|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net7.0-android|AnyCPU'">
|
||||||
<AndroidPackageFormat>apk</AndroidPackageFormat>
|
<AndroidPackageFormat>apk</AndroidPackageFormat>
|
||||||
<RuntimeIdentifiers>android-arm64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>android-arm64;android-x64</RuntimeIdentifiers>
|
||||||
<AndroidCreatePackagePerAbi>True</AndroidCreatePackagePerAbi>
|
<AndroidCreatePackagePerAbi>True</AndroidCreatePackagePerAbi>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(TargetFramework)'=='net7.0-ios'">
|
<PropertyGroup Condition="'$(TargetFramework)'=='net7.0-ios'">
|
||||||
|
<CreatePackage>false</CreatePackage>
|
||||||
|
<CodesignProvision>Automatic</CodesignProvision>
|
||||||
<ProvisioningType>manual</ProvisioningType>
|
<ProvisioningType>manual</ProvisioningType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net7.0-ios|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net7.0-ios|AnyCPU'">
|
||||||
<CreatePackage>false</CreatePackage>
|
|
||||||
<CodesignProvision>Automatic</CodesignProvision>
|
|
||||||
<CodesignKey>iPhone Developer</CodesignKey>
|
<CodesignKey>iPhone Developer</CodesignKey>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net7.0-ios|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net7.0-ios|AnyCPU'">
|
||||||
<CreatePackage>false</CreatePackage>
|
|
||||||
<CodesignProvision>Automatic</CodesignProvision>
|
|
||||||
<CodesignKey>iPhone Distribution</CodesignKey>
|
<CodesignKey>iPhone Distribution</CodesignKey>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -69,5 +71,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
|
||||||
|
<PackageReference Include="sqlite-net-pcl" Version="1.8.116" />
|
||||||
|
<PackageReference Include="SQLitePCLRaw.bundle_green" Version="2.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
50
App/MainPage.xaml.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using Blahblah.FlowerStory.Data;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Blahblah.FlowerStory
|
||||||
|
{
|
||||||
|
public partial class MainPage : ContentPage
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
readonly FlowerDatabase database;
|
||||||
|
|
||||||
|
private readonly ILogger logger;
|
||||||
|
public MainPage(FlowerDatabase database, ILogger<MainPage> logger)
|
||||||
|
{
|
||||||
|
this.logger = logger;
|
||||||
|
|
||||||
|
this.database = database;
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCounterClicked(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (count == 1)
|
||||||
|
CounterBtn.Text = $"Clicked {count} time";
|
||||||
|
else
|
||||||
|
CounterBtn.Text = $"Clicked {count} times";
|
||||||
|
|
||||||
|
SemanticScreenReader.Announce(CounterBtn.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnAppearing()
|
||||||
|
{
|
||||||
|
base.OnAppearing();
|
||||||
|
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var list = await database.GetFlowers();
|
||||||
|
logger.LogInformation("got {count} flowers.", list.Count);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.LogError("error occurs, {exception}", ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,7 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using Blahblah.FlowerStory.Data;
|
||||||
|
#if DEBUG
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Blahblah.FlowerStory
|
namespace Blahblah.FlowerStory
|
||||||
{
|
{
|
||||||
@ -22,6 +25,9 @@ namespace Blahblah.FlowerStory
|
|||||||
builder.Logging.AddDebug();
|
builder.Logging.AddDebug();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
builder.Services.AddSingleton<MainPage>();
|
||||||
|
builder.Services.AddSingleton<FlowerDatabase>();
|
||||||
|
|
||||||
return builder.Build();
|
return builder.Build();
|
||||||
}
|
}
|
||||||
}
|
}
|
Before Width: | Height: | Size: 228 B After Width: | Height: | Size: 228 B |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
67
Doc/Flower Story - Database.md
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
# Flower Story - Database
|
||||||
|
|
||||||
|
## users
|
||||||
|
| column | type | isnull | description |
|
||||||
|
|---------- |--------------|:------:|-------------|
|
||||||
|
| uid | unique int | no |
|
||||||
|
| id | text | no | 用户 id
|
||||||
|
| password | text | no | 加盐密码 [<sup>1</sup>](#ref-anchor-1)
|
||||||
|
| level | integer | no | 用户级别 [<sup>2</sup>](#ref-anchor-2)
|
||||||
|
| regdate | numeric | no | 注册日期
|
||||||
|
| activedate | numeric | | 最后活跃日期
|
||||||
|
| name | text | no | 用户名称
|
||||||
|
| email | text | | 邮箱
|
||||||
|
| mobile | text | | 联系电话
|
||||||
|
---
|
||||||
|
1. <span id="ref-anchor-1"></span>密码存储为 `sha256(password + uid + salt)`
|
||||||
|
2. <span id="ref-anchor-2"></span>级别暂定如下
|
||||||
|
* -1: disabled
|
||||||
|
* 0: user
|
||||||
|
* 99: admin
|
||||||
|
---
|
||||||
|
|
||||||
|
## categories
|
||||||
|
| column | type | isnull | description |
|
||||||
|
|---------- |--------------|:------:|-------------|
|
||||||
|
| cid | unique int | no |
|
||||||
|
| name | text | no | 花草种类名称
|
||||||
|
---
|
||||||
|
|
||||||
|
## flowers
|
||||||
|
| column | type | isnull | description |
|
||||||
|
|---------- |--------------|:------:|-------------|
|
||||||
|
| fid | unique int | no |
|
||||||
|
| categoryid | integer | no | 种类 id
|
||||||
|
| name | text | no | 花草名称
|
||||||
|
| datebuy | numeric | no | 购买时间
|
||||||
|
| cost | real | | 金额
|
||||||
|
| purchase | text | | 购入渠道
|
||||||
|
| photo | blob | | 靓照 [<sup>3</sup>](#ref-anchor-3)
|
||||||
|
---
|
||||||
|
3. <span id="ref-anchor-3"></span>若数据为 `NULL`,则读取 `/assets/$uid/photos/$fid.jpg` 显示为购买时的照片
|
||||||
|
---
|
||||||
|
|
||||||
|
## events
|
||||||
|
| column | type | isnull | description |
|
||||||
|
|---------- |--------------|:------:|-------------|
|
||||||
|
| eid | unique int | no |
|
||||||
|
| name | text | | 事件名称 [<sup>4</sup>](#ref-anchor-4)
|
||||||
|
| unique | integer | | 是否唯一 [<sup>5</sup>](#ref-anchor-5)
|
||||||
|
---
|
||||||
|
4. <span id="ref-anchor-4"></span>事件名称,如购买、出生、换盆、浇水、施肥、发芽、开花、落叶、修剪、生病、死亡、出售等等
|
||||||
|
5. <span id="ref-anchor-5"></span>事件是否唯一,如购买、出生、死亡、出售这些事件具有唯一性
|
||||||
|
---
|
||||||
|
|
||||||
|
## records
|
||||||
|
| column | type | isnull | description |
|
||||||
|
|---------- |--------------|:------:|-------------|
|
||||||
|
| rid | unique int | no |
|
||||||
|
| eid | integer | no | 事件 id
|
||||||
|
| date | numeric | no | 事件发生日期
|
||||||
|
| byuid | integer | | 操作人 uid
|
||||||
|
| byname | text | | 操作人 [<sup>6</sup>](#ref-anchor-6)
|
||||||
|
| photo | blob | | 事件照片 [<sup>7</sup>](#ref-anchor-7)
|
||||||
|
---
|
||||||
|
6. <span id="ref-anchor-6"></span>操作人名称,不是必须为系统内的人员
|
||||||
|
7. <span id="ref-anchor-7"></span>若数据为 `NULL`,则读取 `/assets/$uid/photos/rid/*.jpg` 显示为该事件关联的照片
|
||||||
|
---
|
@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.7.33711.374
|
VisualStudioVersion = 17.7.33711.374
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FlowerStory", "FlowerStory\FlowerStory.csproj", "{A2EB9F7A-8BB8-4D6D-989C-21C6CF10CE4C}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FlowerStory", "App\FlowerStory.csproj", "{A2EB9F7A-8BB8-4D6D-989C-21C6CF10CE4C}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{A551F94A-1997-4A20-A1E8-157050D92CEF}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@ -17,6 +19,10 @@ Global
|
|||||||
{A2EB9F7A-8BB8-4D6D-989C-21C6CF10CE4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{A2EB9F7A-8BB8-4D6D-989C-21C6CF10CE4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{A2EB9F7A-8BB8-4D6D-989C-21C6CF10CE4C}.Release|Any CPU.Build.0 = Release|Any CPU
|
{A2EB9F7A-8BB8-4D6D-989C-21C6CF10CE4C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{A2EB9F7A-8BB8-4D6D-989C-21C6CF10CE4C}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
{A2EB9F7A-8BB8-4D6D-989C-21C6CF10CE4C}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||||
|
{A551F94A-1997-4A20-A1E8-157050D92CEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A551F94A-1997-4A20-A1E8-157050D92CEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A551F94A-1997-4A20-A1E8-157050D92CEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A551F94A-1997-4A20-A1E8-157050D92CEF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
namespace Blahblah.FlowerStory
|
|
||||||
{
|
|
||||||
public partial class MainPage : ContentPage
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
public MainPage()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnCounterClicked(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
|
|
||||||
if (count == 1)
|
|
||||||
CounterBtn.Text = $"Clicked {count} time";
|
|
||||||
else
|
|
||||||
CounterBtn.Text = $"Clicked {count} times";
|
|
||||||
|
|
||||||
SemanticScreenReader.Announce(CounterBtn.Text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
12
Server/.config/dotnet-tools.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"isRoot": true,
|
||||||
|
"tools": {
|
||||||
|
"dotnet-ef": {
|
||||||
|
"version": "7.0.5",
|
||||||
|
"commands": [
|
||||||
|
"dotnet-ef"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
Server/Controller/UserController.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
Server/Data/FlowerDatabase.cs
Normal 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; }
|
||||||
|
}
|
32
Server/Data/Model/FlowerItem.cs
Normal 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);
|
||||||
|
}
|
29
Server/Data/Model/RecordItem.cs
Normal 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);
|
||||||
|
}
|
32
Server/Data/Model/UserItem.cs
Normal 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);
|
||||||
|
}
|
141
Server/Migrations/20230522090224_InitialCreateDb.Designer.cs
generated
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
83
Server/Migrations/20230522090224_InitialCreateDb.cs
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
141
Server/Migrations/20230522143925_ChangeDateColumnType.Designer.cs
generated
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
85
Server/Migrations/20230522143925_ChangeDateColumnType.cs
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
138
Server/Migrations/FlowerDatabaseModelSnapshot.cs
Normal 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
@ -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();
|
||||||
|
}
|
||||||
|
}
|
31
Server/Properties/launchSettings.json
Normal 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
@ -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
@ -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; }
|
||||||
|
}
|
8
Server/appsettings.Development.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
Server/appsettings.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|