diff --git a/init.sql b/Database/init.sql
similarity index 85%
rename from init.sql
rename to Database/init.sql
index 634dc8e..62bfe65 100644
--- a/init.sql
+++ b/Database/init.sql
@@ -1,4 +1,4 @@
-create table address
+create table if not exists address
(
id serial not null
constraint address_pk
@@ -18,10 +18,10 @@ create table address
country text not null
);
-create unique index address_id_uindex
+create unique index if not exists address_id_uindex
on address (id);
-create table offer
+create table if not exists offer
(
id serial not null
constraint offer_pkey
@@ -40,7 +40,7 @@ create table offer
region text not null
);
-create table consumable
+create table if not exists consumable
(
id serial not null
constraint consumables_pk
@@ -59,10 +59,10 @@ create table consumable
is_deleted boolean default false not null
);
-create unique index consumables_id_uindex
+create unique index if not exists consumables_id_uindex
on consumable (id);
-create table device
+create table if not exists device
(
category text not null,
name text not null,
@@ -80,10 +80,10 @@ create table device
is_deleted boolean default false not null
);
-create unique index device_id_uindex
+create unique index if not exists device_id_uindex
on device (id);
-create table personal
+create table if not exists personal
(
id serial not null
constraint manpower_pk
@@ -101,10 +101,10 @@ create table personal
is_deleted boolean default false not null
);
-create unique index manpower_id_uindex
+create unique index if not exists manpower_id_uindex
on personal (id);
-create table region_subscription
+create table if not exists region_subscription
(
id serial not null
constraint region_subscription_pk
@@ -120,7 +120,7 @@ create table region_subscription
region text not null
);
-create table change
+create table if not exists change
(
id serial not null
constraint change_pk
@@ -136,7 +136,7 @@ create table change
region text not null
);
-create table demand
+create table if not exists demand
(
id serial not null
constraint demand_pk
@@ -153,10 +153,10 @@ create table demand
created_at_timestamp timestamp not null
);
-create index demand_token_index
+create index if not exists demand_token_index
on demand (token);
-create table demand_device
+create table if not exists demand_device
(
id serial not null
constraint demand_device_pk
@@ -174,7 +174,7 @@ create table demand_device
is_deleted boolean not null
);
-create table demand_consumable
+create table if not exists demand_consumable
(
id serial not null
constraint demand_consumable_pk
diff --git a/Database/init_dummy_offers.json b/Database/init_dummy_offers.json
new file mode 100644
index 0000000..e48bf04
--- /dev/null
+++ b/Database/init_dummy_offers.json
@@ -0,0 +1,53 @@
+{
+ "OfferContexts": [
+ {
+ "Address": {
+ "hascoordinates": true,
+ "latitude": "48.13756",
+ "longitude": "11.57490",
+ "is_deleted": false,
+ "street_line_1": "Marienplatz 1",
+ "street_line_2": null,
+ "street_line_3": null,
+ "street_line_4": null,
+ "county": null,
+ "city": "München",
+ "state": null,
+ "postal_code": "80331",
+ "country": "DEUTSCHLAND"
+ },
+ "Offer": {
+ "name": "GermanDummyPirat",
+ "mail": "pirat.hilfsmittel@gmail.com",
+ "phone": "123456",
+ "organisation": "DummyOrganisation",
+ "ispublic": false,
+ "token": "0P2uADVO3Y7Q9YstM7Z08vfjFRhUQE",
+ "timestamp":"2020-05-12 00:00:00.000000",
+ "region": "de"
+ },
+ "Consumables": [
+ {
+ "category": "MASKE",
+ "name": "FFP2 MASKE",
+ "manufacturer": "German Dummy & Co",
+ "ordernumber": 545454,
+ "amount": 100,
+ "unit": "Packung",
+ "annotation": "Nur ein Dummy",
+ "is_deleted": false
+ },
+ {
+ "category": "MASKE",
+ "name": "FFP3 MASKE",
+ "manufacturer": "German Dummy & Co",
+ "ordernumber": 77777,
+ "amount": 50,
+ "unit": "Packung",
+ "annotation": "Nur ein Dummy",
+ "is_deleted": false
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Pirat/DatabaseContext/DatabaseInitialization.cs b/Pirat/DatabaseContext/DatabaseInitialization.cs
new file mode 100644
index 0000000..00d7fe6
--- /dev/null
+++ b/Pirat/DatabaseContext/DatabaseInitialization.cs
@@ -0,0 +1,176 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using Microsoft.EntityFrameworkCore;
+using Newtonsoft.Json;
+using Npgsql;
+using Pirat.Model.Entity.Resource.Common;
+using Pirat.Model.Entity.Resource.Stock;
+
+namespace Pirat.DatabaseContext
+{
+
+ ///
+ /// The related tables if an offer is inserted to the database
+ ///
+ public class OfferContext
+ {
+ [JsonProperty]
+ public AddressEntity Address { get; set; }
+
+ [JsonProperty]
+ public OfferEntity Offer { get; set; }
+
+ [JsonProperty]
+ public List Consumables { get; set; }
+
+ [JsonProperty]
+ public List Devices { get; set; }
+
+ [JsonProperty]
+ public List Personals { get; set; }
+ }
+
+ public class OffersInitialization
+ {
+ [JsonProperty]
+ public List OfferContexts { get; set; }
+ }
+
+ public static class DatabaseInitialization
+ {
+
+ private static readonly string DatabaseInitializationFilesLocation =
+ Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Database");
+
+ private static readonly string DatabaseTableInitializationFile =
+ Path.Combine(DatabaseInitializationFilesLocation, "init.sql");
+
+ ///
+ /// Checks if connection to database can be established. Otherwise exception is thrown.
+ ///
+ public static void CheckConnectionToDatabase()
+ {
+ var connection = new NpgsqlConnection(Environment.GetEnvironmentVariable("PIRAT_CONNECTION"));
+ connection.Open();
+ connection.Dispose();
+ }
+
+ ///
+ /// Create new tables in database if not exist so far. Table create commands are read from init.sql.
+ ///
+ public static void InitDatabaseTables()
+ {
+ CheckConnectionToDatabase();
+
+ var commandsInput = File.ReadAllText(DatabaseTableInitializationFile, Encoding.UTF8);
+
+ var commands = commandsInput.Split(';');
+
+ var tablesBefore = FindExistingTables();
+ Console.Out.WriteLine($"Tables in database:");
+ foreach (var table in tablesBefore)
+ {
+ Console.Out.WriteLine($"{table}");
+ }
+
+ using (NpgsqlConnection connection =
+ new NpgsqlConnection(Environment.GetEnvironmentVariable("PIRAT_CONNECTION")))
+ {
+ connection.Open();
+
+ foreach (var command in commands)
+ {
+ using NpgsqlCommand sqlCommand = new NpgsqlCommand(command + ";", connection);
+ sqlCommand.ExecuteNonQuery();
+ }
+ }
+
+ var tablesAfter = FindExistingTables();
+ foreach (var table in tablesAfter.Except(tablesBefore))
+ {
+ Console.Out.WriteLine($"Created table: {table}");
+ }
+ }
+
+ ///
+ /// The database that is found by using the connection string is initialized with dummy data.
+ /// Dummy data will only be inserted if associated tables are empty.
+ ///
+ public static async void InitDatabaseWithDummyData()
+ {
+ CheckConnectionToDatabase();
+
+ DbContextOptions options =
+ new DbContextOptionsBuilder().UseNpgsql(Environment.GetEnvironmentVariable("PIRAT_CONNECTION")).Options;
+
+ await using var context = new ResourceContext(options);
+ //Insert only dummy values if offer table empty
+ if (!context.offer.Any())
+ {
+ var dummyData = Path.Combine(DatabaseInitializationFilesLocation, "init_dummy_offers.json");
+ var content = File.ReadAllText(dummyData);
+ var offerInit = JsonConvert.DeserializeObject(content);
+ foreach (var offerContext in offerInit.OfferContexts)
+ {
+ var address = (AddressEntity) await offerContext.Address.InsertAsync(context);
+ offerContext.Offer.address_id = address.Id;
+ var offer = (OfferEntity) await offerContext.Offer.InsertAsync(context);
+
+ if (offerContext.Consumables != null)
+ {
+ foreach (var consumable in offerContext.Consumables)
+ {
+ consumable.offer_id = offer.id;
+ await consumable.InsertAsync(context);
+ }
+ }
+
+ if (offerContext.Devices != null)
+ {
+ foreach (var device in offerContext.Devices)
+ {
+ device.offer_id = offer.id;
+ await device.InsertAsync(context);
+ }
+ }
+
+ if (offerContext.Personals != null)
+ {
+ foreach (var personal in offerContext.Personals)
+ {
+ personal.offer_id = offer.id;
+ await personal.InsertAsync(context);
+ }
+ }
+ }
+ }
+ //Insert other dummy data contexts here
+ }
+
+ private static List FindExistingTables()
+ {
+ var existingTables = new List();
+ using (NpgsqlConnection connection =
+ new NpgsqlConnection(Environment.GetEnvironmentVariable("PIRAT_CONNECTION")))
+ {
+ connection.Open();
+ using NpgsqlCommand c = new NpgsqlCommand("SELECT table_name " +
+ "FROM information_schema.tables " +
+ "WHERE table_schema = 'public' " +
+ "AND table_type = 'BASE TABLE';", connection);
+
+ using NpgsqlDataReader rdr = c.ExecuteReader();
+ while (rdr.Read())
+ {
+ existingTables.Add(rdr.GetString(0));
+ }
+ }
+
+ return existingTables;
+ }
+ }
+}
diff --git a/Pirat/Pirat.csproj b/Pirat/Pirat.csproj
index 3de2576..17917f6 100644
--- a/Pirat/Pirat.csproj
+++ b/Pirat/Pirat.csproj
@@ -37,6 +37,11 @@
+
+
+
+
+
@@ -67,4 +72,10 @@
$(NoWarn);1591
+
+
+ Always
+
+
+
diff --git a/Pirat/Program.cs b/Pirat/Program.cs
index 015c4da..658369b 100644
--- a/Pirat/Program.cs
+++ b/Pirat/Program.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
-using Npgsql;
+using Pirat.DatabaseContext;
namespace Pirat
{
@@ -13,7 +13,13 @@ public class Program
public static void Main(string[] args)
{
CheckEnvironmentVariables();
- CheckConnectionToDatabase();
+
+ DatabaseInitialization.CheckConnectionToDatabase();
+ var initTables = string.Equals(Environment.GetEnvironmentVariable("PIRAT_INIT_DB_TABLES_IF_NOT_EXIST"), "true", StringComparison.Ordinal);
+ var initData = string.Equals(Environment.GetEnvironmentVariable("PIRAT_INIT_DUMMY_DATA_IF_NOT_EXIST"),"true", StringComparison.Ordinal);
+ if (initTables) DatabaseInitialization.InitDatabaseTables();
+ if (initData) DatabaseInitialization.InitDatabaseWithDummyData();
+
CreateHostBuilder(args).Build().Run();
}
@@ -35,7 +41,10 @@ public static void CheckEnvironmentVariables()
"PIRAT_ADMIN_KEY",
"PIRAT_SWAGGER_PREFIX_PATH",
- "PIRAT_WEBAPP_ENVIRONMENT"
+ "PIRAT_WEBAPP_ENVIRONMENT",
+
+ "PIRAT_INIT_DB_TABLES_IF_NOT_EXIST",
+ "PIRAT_INIT_DUMMY_DATA_IF_NOT_EXIST"
};
foreach (var requiredEnvironmentVariable in requiredEnvironmentVariables)
{
@@ -46,14 +55,6 @@ public static void CheckEnvironmentVariables()
}
}
- public static void CheckConnectionToDatabase()
- {
- var connection = new NpgsqlConnection(Environment.GetEnvironmentVariable("PIRAT_CONNECTION"));
- connection.Open();
- connection.Dispose();
- }
-
-
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
diff --git a/README.md b/README.md
index 23654bc..d95193f 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,9 @@ See https://dotnet.microsoft.com/download/dotnet-core/3.1 to get the SDK
#### Database
-This program uses a PostgreSQL database. The database definition is in `init.sql`.
+This program uses a PostgreSQL database. The database definition is in `Database/init.sql`.
+
+Dummy data that is possible loaded into the database (see section Environment Variables) is in `Database`.
#### Compile
@@ -57,6 +59,11 @@ The following environment variables are available, most of them are required.
* PIRAT_GOOGLE_API_KEY
* PIRAT_GOOGLE_RECAPTCHA_SECRET
+**Database Initialization**
+
+* PIRAT_INIT_DB_TABLES_IF_NOT_EXIST - If set to `true` tables that do not exist so far are added to the schema.
+* PIRAT_INIT_DUMMY_DATA_IF_NOT_EXIST - Insert predefined dummy data into the tables if set to `true`. If tables are not empty, the dummy data gets not inserted.
+
Example:
@@ -77,6 +84,9 @@ PIRAT_INTERNAL_RECEIVER_MAIL=mail@pirat-tool.com
PIRAT_GOOGLE_API_KEY=KKKKEEEEYYYYY
PIRAT_GOOGLE_RECAPTCHA_SECRET=SSSSEEECCCRRREEEEEETTTTTTT
+
+PIRAT_INIT_DB_TABLES_IF_NOT_EXIST=true
+PIRAT_INIT_DUMMY_DATA_IF_NOT_EXIST=true
```
diff --git a/test-database_docker-compose.yml b/test-database_docker-compose.yml
index 0c0d80d..3e54886 100644
--- a/test-database_docker-compose.yml
+++ b/test-database_docker-compose.yml
@@ -11,4 +11,4 @@ services:
ports:
- 5432:5432
volumes:
- - ./init.sql:/docker-entrypoint-initdb.d/init.sql
+ - ./Database/init.sql:/docker-entrypoint-initdb.d/init.sql