diff --git a/cms/backend/postgresql/hawaii-config.PostgreSql.json b/cms/backend/postgresql/hawaii-config.PostgreSql.json new file mode 100644 index 0000000..765d984 --- /dev/null +++ b/cms/backend/postgresql/hawaii-config.PostgreSql.json @@ -0,0 +1,233 @@ +{ + "$schema": "../schemas/hawaii.draft-01.schema.json", + "data-source": { + "database-type": "postgresql", + "connection-string": "Host=localhost;Database=cms-db;User ID=postgres;" + }, + "mssql": { + "set-session-context": false + }, + "runtime": { + "rest": { + "enabled": true, + "path": "/api" + }, + "graphql": { + "enabled": true, + "path": "/graphql", + "allow-introspection": true + }, + "host": { + "mode": "Production", + "cors": { + "origins": [ "http://localhost:3000" ], + "allow-credentials": true + }, + "authentication": { + "provider": "AzureAD", + "jwt": { + "audience": "e98794ab-cdaa-4ed3-ad08-0552c47254e2", + "issuer": "https://login.microsoftonline.com/72f988bf-86f1-41af-91ab-2d7cd011db47/v2.0" + } + } + } + }, + "entities": { + "User": { + "source": "users", + "rest": true, + "graphql": true, + "permissions": [ + { + "role": "anonymous", + "actions": [] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create", + "policy": { + "request": "@claims.oid eq @body.guid" + }, + "fields": { + "include": [ "*" ] + } + }, + { + "action": "read", + "policy": { + "database": "@claims.oid eq @item.guid" + }, + "fields": { + "include": [ "*" ] + } + }, + { + "action": "update", + "policy": { + "database": "@claims.oid eq @item.guid" + }, + "fields": { + "include": [ "*" ], + "exclude": [ "email" ] + } + }, + { + "action": "delete", + "policy": { + "database": "@claims.oid eq @item.guid" + }, + "fields": { + "include": [ "*" ] + } + } + ] + } + ], + "relationships": { + "articles": { + "cardinality": "many", + "target.entity": "Article", + "source.fields": [ "guid" ], + "target.fields": [ "author_id" ] + } + } + }, + "Article": { + "source": "articles", + "rest": true, + "graphql": true, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "read", + "policy": { + "database": "@item.status eq 2" + }, + "fields": { + "include": [ "*" ], + "exclude": [] + } + } + ] + }, + { + "role": "authenticated", + "actions": [ + "create", + { + "action": "read", + "policy": { + "database": "@claims.oid eq @item.author_id" + }, + "fields": { + "include": [ "*" ] + } + }, + { + "action": "update", + "policy": { + "database": "@claims.oid eq @item.author_id" + }, + "fields": { + "include": [ "*" ] + } + }, + { + "action": "delete", + "policy": { + "database": "@claims.oid eq @item.author_id" + }, + "fields": { + "include": [ "*" ] + } + } + ] + } + ], + "relationships": { + "users": { + "cardinality": "one", + "target.entity": "User", + "source.fields": [ "author_id" ], + "target.fields": [ "guid" ] + }, + "article_statuses": { + "cardinality": "one", + "target.entity": "Status", + "source.fields": [ "status" ], + "target.fields": [ "id" ] + } + } + }, + "Status": { + "source": "article_statuses", + "rest": true, + "graphql": true, + "permissions": [ + { + "role": "anonymous", + "actions": [ "read" ] + }, + { + "role": "authenticated", + "actions": [ "read" ] + } + ], + "relationships": { + "articles": { + "cardinality": "many", + "target.entity": "Article", + "source.fields": [ "id" ], + "target.fields": [ "status" ] + } + } + }, + "ArticleDetailed": { + "source": { + "type": "view", + "object": "articles_detailed", + "key-fields": [ "id" ] + }, + "rest": true, + "graphql": true, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "read", + "policy": { + "database": "@item.status eq 'published'" + }, + "fields": { + "include": [ "*" ], + "exclude": [] + } + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "read", + "policy": { + "database": "@claims.oid eq @item.author_id" + }, + "fields": { + "include": [ "*" ], + "exclude": [] + } + } + ] + } + ] + } + } + +} + diff --git a/cms/backend/postgresql/init-cms-db.sql b/cms/backend/postgresql/init-cms-db.sql new file mode 100644 index 0000000..aacf3bf --- /dev/null +++ b/cms/backend/postgresql/init-cms-db.sql @@ -0,0 +1,112 @@ +-- Must already be connected to cms-db at this point; Postgres does not support database context switching + +DROP VIEW IF EXISTS articles_detailed; +DROP TABLE IF EXISTS articles; +DROP TABLE IF EXISTS users; +DROP TABLE IF EXISTS article_statuses; + +-- DDL +CREATE TABLE article_statuses( + id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name varchar(100) NOT NULL +); + +CREATE TABLE users( + guid varchar(50) PRIMARY KEY, + fname varchar(100) NOT NULL, + lname varchar(100) NOT NULL, + email varchar(100) NOT NULL CHECK(email like '_%@_%._%') +); + +CREATE TABLE articles( + id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + title varchar(100) NOT NULL, + body varchar NOT NULL, + published timestamp DEFAULT timezone('utc', now()), + status int NOT NULL, + FOREIGN KEY (status) REFERENCES article_statuses(id) + ON UPDATE CASCADE, -- ON DELETE will reject/cannot delete a status from the database if an article is assigned to it + author_id varchar(50) NOT NULL, + FOREIGN KEY (author_id) REFERENCES users(guid) + ON UPDATE CASCADE + ON DELETE CASCADE -- ON DELETE of author from user table, all associated articles are trashed +); + +-- Ease-of-use view for article/author/status join +CREATE VIEW articles_detailed AS +SELECT a.id, a.title, a.body, a.published, +u.fname || ' ' || u.lname AS author_name, u.email AS author_email, +s.name AS status +FROM articles AS a +JOIN users AS u +ON a.author_id = u.guid +JOIN article_statuses AS s +ON a.status = s.id; + +-- DML +INSERT INTO article_statuses (name) VALUES ('draft'), ('published'); +INSERT INTO users (guid, fname, lname, email) VALUES (1, 'Sean', 'Leonard', 'sean.leonard@microsoft.com'); +INSERT INTO articles (title, body, status, author_id) +VALUES ('lorem ipsum', '# Thebis meae grege prima de apertas invitumque + +## Precor sibi + +Lorem markdownum spemque aetas Olympum saevit, Hippothousque recurvas loquenti +attulit a. Multa ora nam mea albentibus heros *foedantem Memnonis* notas; me +tibi peregit! Increpat deserti; ire tua ars +[cunctisque](http://sensim-pugnae.org/discite.html) locus, pudet caligine, mihi +poplite. Capillos rubore. + +- Studiis visumque +- Veteris nostras sit heros est abstinet terris +- Exsiluere infuso scopulos traditque iunctim cura +- Tamen est cessura venisset constiterant cives iratus +- Succedere demens gutture affata +- Nec tamen + +## Verti laeta pedes mea nubibus tenet + +*Fugat* obortae. Sidera ratibusque precantia viro est Phorcidas; certe in in +cetera, guttis nec. Quam fortunaque antrum carbasa responsa promittet summasque +tympana *carchesia* nubibus? Aliqua accipiunt illo parente tuae eripitur bibulis +abstulit natis iuvenci. Inemptum et nervis postquam at longo tuo idem antiquum +meruisse in. + + publishing_program(5); + fios = lock_commerce_uml; + thyristor += 1; + if (-1 >= artificial) { + webOpacity = brouter + 95; + } + snippet(bug); + +## Piget sanguine numen est + +Fixus ita munere optantemque parte, velox inproba: Amnis *ibi invidiosa senex* +necis nox! Antemnas maxima uni videor, voce fures cecidit altis navigiis genis, +victorem in *ictus coloni* pendens. Post ira velle tempusque sospes miranti, +homines contermina invita distuleratque Elide corpore! Aliquid nec sanguis +tardior Alcimedon; **debes serta** vipereasque veste celeberrima vultus *Ardea*? + +> Inania tuus altos sinat; stringit suamque tempora +> [incessere](http://et-sed.net/duo.html) resilire, unda. Lignoque timeri, vale +> pater dolet nec procerum siquem quibus: militia sanctique, mente. Sua iners +> huic bene. Quod *aede*, Peneia motu [arripit +> fumos](http://corpore-aderant.net/), rabiemque Phryges me quemque metus +> subductaque cervo: quantum plumas, a. Cervi seriemque postquam genetivaque +> umerique: Ilus vir, forma litus celeberrimus feminea at relabi et spirat +> stridores si. + +Dicta templa illi auctor mansit tura aether dat umbram temptemus maluit +**Hyleusque**, nox excussit sed patet aequatam perlucidus menso. Fretaque +fibula, maduere dixerat rapienda; illi ipse, ut si vel volucrum fateor +patriumque! Tibi pronaque, heu vincar, conata densior movit, nova ipse, turba +nec inclusa mortale annis caput! + +Spectans silva et milia, dare mediam, optari instigant ingenti fortuna +**fugientibus questa lingua** memori sorores *potentia*. Nec inprovisoque sunt +aequoreos mentis tua, magnos medicas, casu, errabant. Sincera hic teneros haec +Emathiis, quamvis et terris terrae non animalia utque; est. Stant novi, Parnasi, +Solem facies. Movere tamen, avitum abstuleris in inde properare refert memorata +poste, Aeas.', 2, 1); + diff --git a/cms/backend/postgresql/init-db.bat b/cms/backend/postgresql/init-db.bat new file mode 100644 index 0000000..9b34f1d --- /dev/null +++ b/cms/backend/postgresql/init-db.bat @@ -0,0 +1,7 @@ +@echo off + +dropdb -U postgres --if-exists cms-db + +Rem Only create schema if cms-db was successfully created +createdb -U postgres cms-db && psql -d cms-db -U postgres -f init-cms-db.sql || echo encountered an issue creating cms-db, please resolve and re-run or try to use SSMS/Azure Data Studio + diff --git a/cms/backend/postgresql/run-new.bat b/cms/backend/postgresql/run-new.bat new file mode 100644 index 0000000..aeef4c9 --- /dev/null +++ b/cms/backend/postgresql/run-new.bat @@ -0,0 +1,4 @@ +@echo off + + +CALL init-db && CALL run-server || echo Failed to initialize db, safely exiting. diff --git a/cms/backend/postgresql/run-server.bat b/cms/backend/postgresql/run-server.bat new file mode 100644 index 0000000..4332f45 --- /dev/null +++ b/cms/backend/postgresql/run-server.bat @@ -0,0 +1,3 @@ +@echo off + +dotnet run --project ../../../../hawaii-engine/DataGateway.Service --ConfigFileName ../../hawaii-samples/cms/backend/postgresql/hawaii-config.PostgreSql.json diff --git a/cms/backend/postgresql/run-server.sh b/cms/backend/postgresql/run-server.sh new file mode 100644 index 0000000..41e84d2 --- /dev/null +++ b/cms/backend/postgresql/run-server.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +dotnet run --project ../../../../hawaii-engine/DataGateway.Service --ConfigFileName ../../hawaii-samples/cms/backend/postgresql/hawaii-config.PostgreSql.json \ No newline at end of file