Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(v3): finish user slice (DEV-671) #2078

Merged
merged 48 commits into from Jul 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
5a964e5
start with C4 documentation
Jun 15, 2022
fb8737a
refactor UserId
Jun 15, 2022
83a3480
add imports for UserId
Jun 15, 2022
697fc6b
separate username and email checks
Jun 15, 2022
093a654
add update methods
Jun 15, 2022
efab594
refactor id
Jun 15, 2022
e09f4b9
use password hash instead of password
Jun 15, 2022
3de2346
add negative tests
Jun 15, 2022
fc2064d
refactor UserHandlerSpec
Jun 15, 2022
161dc8c
Merge branch 'main' into wip/dev-671-finish-user-slice
Jun 16, 2022
c416213
add shared test data
Jun 17, 2022
d796109
use shared test data in tests
Jun 17, 2022
10f9cc5
finish user slice
Jun 17, 2022
dae79b7
add all user projects to root
Jun 17, 2022
1898bb0
remove unnecessary log output
Jun 17, 2022
a395d3f
add architecture documentation
Jun 17, 2022
9115544
add sequence diagram with mermaid
Jun 20, 2022
a6b428e
cleanup code
Jun 21, 2022
a598df5
bump ZioLoggingVersion
Jun 21, 2022
cd4a9e9
refactor tests
Jun 21, 2022
0e6eb65
implement feedback from review
Jun 21, 2022
7dde874
Merge branch 'main' into wip/dev-671-finish-user-slice
Jun 21, 2022
e16936e
fix failing test
Jun 22, 2022
614d9af
Merge branch 'main' into wip/dev-671-finish-user-slice
subotic Jun 24, 2022
71a0db0
Update Id.scala
Jun 28, 2022
6d3f774
rename test data
Jun 28, 2022
965d106
add password strength as value object
Jun 28, 2022
cc7b975
move taps to end of method
Jun 28, 2022
d3bc8b4
simplify test
Jun 28, 2022
4bcc5d6
refactor user to return a validation
Jun 29, 2022
e6f347b
remove throwables from shared test data
Jun 29, 2022
8a957e9
refactor tests
Jun 29, 2022
846ed1a
remove duplicated line
Jun 29, 2022
921af65
correct typo
Jun 29, 2022
47f22c6
Merge branch 'main' into wip/dev-671-finish-user-slice
Jun 29, 2022
c4523c4
remove sha-1 support
Jun 29, 2022
a9adc11
remove unsafeMake as we don't need them
Jun 29, 2022
83e5fdc
add placeholder to empty files to remove warnings
Jun 30, 2022
9f3d04f
return error instead of throw
Jun 30, 2022
f4b1e53
update docs
Jun 30, 2022
9b6045a
improve handling of value objects
Jun 30, 2022
fc6c182
add unsafeMake again
Jun 30, 2022
d25d4a7
Update UsersRouteADM.scala
Jun 30, 2022
a37ef0a
Merge branch 'main' into wip/dev-671-finish-user-slice
Jun 30, 2022
3a48489
Merge branch 'main' into wip/dev-671-finish-user-slice
Jul 4, 2022
515ff0a
refactor UserDomainSpec
Jul 4, 2022
2adb627
Update Makefile
Jul 4, 2022
93835c2
add slf4j dependency
Jul 4, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 0 additions & 5 deletions Makefile
Expand Up @@ -203,11 +203,6 @@ test-repository-upgrade: build init-db-test-minimal ## runs DB upgrade integrati

.PHONY: test
test: build ## runs all tests
sbt -v "schemaApi/test"
sbt -v "schemaCore/test"
sbt -v "schemaRepo/test"
sbt -v "schemaRepoEventStoreService/test"
sbt -v "schemaRepoSearchService/test"
sbt -v "shared/test"
sbt -v "sipi/test"
sbt -v "userCore/test"
Expand Down
90 changes: 16 additions & 74 deletions build.sbt
Expand Up @@ -28,7 +28,7 @@ lazy val buildSettings = Seq(
lazy val rootBaseDir = ThisBuild / baseDirectory

lazy val root: Project = Project(id = "root", file("."))
.aggregate(webapi, apiMain)
.aggregate(webapi, sipi, shared, valueObjects, userCore, userHandler, userRepo, userInterface)
.enablePlugins(GitVersioning, GitBranchPrompt)
.settings(
// values set for all sub-projects
Expand Down Expand Up @@ -232,16 +232,6 @@ lazy val webapiJavaTestOptions = Seq(
// DSP's new codebase
//////////////////////////////////////

lazy val apiMain = project
.in(file("dsp-api-main"))
.settings(
name := "dsp-api-main",
libraryDependencies ++= Dependencies.dspApiMainLibraryDependencies,
resolvers += "Sonatype" at "https://oss.sonatype.org/content/repositories/snapshots",
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)
.dependsOn(schemaCore, schemaRepo, schemaApi)

// Value Objects project

lazy val valueObjects = project
Expand All @@ -252,57 +242,6 @@ lazy val valueObjects = project
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)

// Schema projects

lazy val schemaApi = project
.in(file("dsp-schema/api"))
.settings(
name := "schemaApi",
libraryDependencies ++= Dependencies.schemaApiLibraryDependencies,
resolvers += "Sonatype" at "https://oss.sonatype.org/content/repositories/snapshots",
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)
.dependsOn(schemaCore)

lazy val schemaCore = project
.in(file("dsp-schema/core"))
.settings(
name := "schemaCore",
libraryDependencies ++= Dependencies.schemaCoreLibraryDependencies,
resolvers += "Sonatype" at "https://oss.sonatype.org/content/repositories/snapshots",
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)

lazy val schemaRepo = project
.in(file("dsp-schema/repo"))
.settings(
name := "schemaRepo",
libraryDependencies ++= Dependencies.schemaRepoLibraryDependencies,
resolvers += "Sonatype" at "https://oss.sonatype.org/content/repositories/snapshots",
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)
.dependsOn(schemaCore)

lazy val schemaRepoEventStoreService = project
.in(file("dsp-schema/repo-eventstore-service"))
.settings(
name := "schemaRepoEventstoreService",
libraryDependencies ++= Dependencies.schemaRepoEventStoreServiceLibraryDependencies,
resolvers += "Sonatype" at "https://oss.sonatype.org/content/repositories/snapshots",
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)
.dependsOn(schemaRepo)

lazy val schemaRepoSearchService = project
.in(file("dsp-schema/repo-search-service"))
.settings(
name := "dsp-schema-repo-search-service",
libraryDependencies ++= Dependencies.schemaRepoSearchServiceLibraryDependencies,
resolvers += "Sonatype" at "https://oss.sonatype.org/content/repositories/snapshots",
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)
.dependsOn(schemaRepo)

// User projects

lazy val userInterface = project
Expand Down Expand Up @@ -335,10 +274,14 @@ lazy val userHandler = project
libraryDependencies ++= Dependencies.userHandlerLibraryDependencies,
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)
.dependsOn(shared, userCore, userRepo % "test->test") //userHandler tests need mock implementation of UserRepo
.dependsOn(
shared,
userCore % "compile->compile;test->test",
userRepo % "test->test" //userHandler tests need mock implementation of UserRepo
)

lazy val userCore = project
.in(file("dsp-user/core"))
lazy val userRepo = project
.in(file("dsp-user/repo"))
.settings(
scalacOptions ++= Seq(
"-feature",
Expand All @@ -347,14 +290,14 @@ lazy val userCore = project
"-Yresolve-term-conflict:package",
"-Ymacro-annotations"
),
name := "userCore",
libraryDependencies ++= Dependencies.userCoreLibraryDependencies,
name := "userRepo",
libraryDependencies ++= Dependencies.userRepoLibraryDependencies,
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)
.dependsOn(shared)
.dependsOn(shared, userCore % "compile->compile;test->test")

lazy val userRepo = project
.in(file("dsp-user/repo"))
lazy val userCore = project
.in(file("dsp-user/core"))
.settings(
scalacOptions ++= Seq(
"-feature",
Expand All @@ -363,12 +306,11 @@ lazy val userRepo = project
"-Yresolve-term-conflict:package",
"-Ymacro-annotations"
),
name := "userRepo",
libraryDependencies ++= Dependencies.userRepoLibraryDependencies,
name := "userCore",
libraryDependencies ++= Dependencies.userCoreLibraryDependencies,
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)
.dependsOn(shared, userCore)
//.dependsOn(userHandler % "compile->compile;test->test", userDomain)
.dependsOn(shared)

lazy val shared = project
.in(file("dsp-shared"))
Expand Down
27 changes: 27 additions & 0 deletions docs/architecture/docs/http-request-flow-with-events.md
@@ -0,0 +1,27 @@
## Example for an HTTP Request Flow with Events

### Create a User
```mermaid
sequenceDiagram
autonumber
user ->> userRoute: "sends HTTP request"
userRoute ->> userRoute: "validates input (payload) and creates value objects"
userRoute ->> userHandler: "sends value objects"
userHandler ->> userRepo: "reserves username"
userRepo ->> eventStoreService: "reserves username"
eventStoreService ->> eventStoreService: "checks if username exists"
eventStoreService ->> eventStoreService: "reserves username"
userHandler ->> userDomain: "calls User.make() with value objects"
userDomain ->> userDomain: "creates userDomainEntity + userCreatedEvent(who, what)"
userDomain ->> userHandler: "returns (userDomainEntity + userCreatedEvent)"
userHandler ->> userRepo: "storeUser(userDomainEntity + userCreatedEvent)"
userRepo ->> eventStoreService: "storeUser(userDomainEntity + userCreatedEvent)"
eventStoreService ->> eventStoreService: "store event(s), userCreatedEvent(who, what, when(!))"
eventStoreService ->> eventListener: "publishEvent(userCreatedEvent)"
eventListener ->> triplestoreService: "writeToTsService(E)"
triplestoreService ->> triplestoreService: "SPARQL update - write user to triplestore"
eventListener ->> arkService: "writeToArkService(E)"
arkService ->> arkService: "create ARK(URL)"
eventListener ->> elasticSearchService: "writeToEsService(E)"
elasticSearchService ->> elasticSearchService: "write"
```
@@ -1,4 +1,4 @@
HTTP Request Flow
## HTTP Request Flow V2 vs. V3

V1 / V2 / admin:
```mermaid
Expand Down
8 changes: 8 additions & 0 deletions docs/architecture/users.dsl
@@ -0,0 +1,8 @@
# person <name> [description] [tags]
user = person "A user / client" "A user of DSP, regardless if known/unknow or its role"
#userUnknown = person "Unknown user" "An unknown user of DSP"
#userUnknown = person "Unknown user" "An unknown user of DSP"
#userKnown = person "Known user" "A logged-in user of DSP"
#userSysAdmin = person "System Admin" "A system admin of DSP"
#userProjectAdmin = person "Project Admin" "A project administrator"
#userProjectMember = person "Project Member" "A project member"
irinaschubert marked this conversation as resolved.
Show resolved Hide resolved
169 changes: 163 additions & 6 deletions docs/architecture/workspace.dsl
@@ -1,21 +1,178 @@
workspace {
workspace "Architecture Diagrams for DSP" "This is a collection of diagrams for the DSP architecture" {
# https://github.com/structurizr/dsl/blob/master/docs/language-reference.md
# for an example, see https://structurizr.com/dsl?example=big-bank-plc



# static model
model {
user = person "User"
softwareSystem = softwareSystem "Software System"
!include users.dsl

enterprise "DSP - DaSCH Service Platform" {
# softwareSystem <name> [description] [tags]
dspJsLib = softwaresystem "JS-LIB" "Layer between DSP-API and DSP-APP"
dspApp = softwaresystem "DSP-APP" "admin.dasch.swiss"
dspTools = softwaresystem "DSP-TOOLS" "CLI for DSP-API"
fuseki = softwaresystem "Fuseki Triplestore" "RDF database" "Database"
sipi = softwaresystem "SIPI" "IIIF image server"
arkResolver = softwaresystem "ARK Resolver" "Forwards ARK URLs to DSP-APP URLs"
dspApi = softwareSystem "DSP-API" "api.dasch.swiss" {
# container <name> [description] [technology] [tags]

eventStoreService = container "Event Store Service"
eventListener = container "Event Listener"
triplestoreService = container "Triplestore Service"
arkService = container "ARK Service"
elasticSearchService = container "Elastic Search Service"

sharedProject = container "Shared Project" "The project that handles shared entities" {
valueObjectsPackage = component "ValueObjects Package" "The package that provides value objects"
errorPackage = component "Error Package" "The package that provides errors"
}

webapiProject = container "Webapi" "The project that wraps webapi V2"

projectSlice = container "Project Slice" "The slice that handles projects"
roleSlice = container "Role Slice" "The slice that handles roles"
schemaSlice = container "Schema Slice" "The slice that handles schemas"
resourceSlice = container "Resource Slice" "The slice that handles resources"
listSlice = container "List Slice" "The slice that handles lists"
routes = container "Routes" "The slice that provides all routes"

userSlice = container "User Slice" "The slice that handles users" {
userCore = component "User Core"
userDomain = component "User Domain"
userHandler = component "User Handler"

userRepo = component "User Repo (API)"
userRepoLive = component "User Repo Live (Implementation)"
userRepoMock = component "User Repo Mock (Implementation for Tests)"

userRoute = component "User Route"
}

}
}

# relationships between users and software systems
user -> dspApp "Uses [Browser]"
user -> arkResolver "Uses [Browser]"
user -> dspTools "Uses [CLI]"

# relationships to/from software systems
dspApp -> dspJsLib
dspJsLib -> dspApi
dspTools -> dspApi
dspApi -> fuseki
dspApi -> sipi
dspTools -> sipi

# relationships to/from containers
webapiProject -> sharedProject "depends on"
projectSlice -> sharedProject "depends on"
roleSlice -> sharedProject "depends on"
schemaSlice -> sharedProject "depends on"
resourceSlice -> sharedProject "depends on"
listSlice -> sharedProject "depends on"
routes -> sharedProject "depends on"
userSlice -> sharedProject "depends on"

# relationships to/from components
userRepo -> userCore "depends on"
userRepoLive -> userCore "depends on"
userRepoMock -> userCore "depends on"
userRoute -> userCore "depends on"

userRepoLive -> userRepo "implements"
userRepoMock -> userRepo "implements"

userCore -> userDomain "contains"
userCore -> userHandler "contains"

user -> softwareSystem "Uses"
}

views {
systemContext softwareSystem "Diagram1" {
systemlandscape "SystemLandscape" "System Landscape of DSP-API" {
include *
autoLayout
}

# systemContext <software system identifier> [key] [description]
systemContext dspApi "SystemContextDspApi" "DSP-API System Context" {
include *
autoLayout
}

# container <software system identifier> [key] [description]
container dspApi "ContainerDspApi" "Containers of DSP-API" {
include *
autoLayout
}

# component <container identifier> [key] [description]
component userSlice "ComponentsOfUserSlice" "Components of the User Slice" {
include *

}

component SharedProject "ComponentsOfSharedProject" "Components of the Shared Project" {
include *
autoLayout
}

# dynamic <*|software system identifier|container identifier> [key] [description]
dynamic userSlice "HttpRequestWithEventsCreateUser" "Example workflow for a HTTP request with events (create user)" {
user -> userRoute "sends HTTP request to"
userRoute -> userRoute "validates input and creates value objects"
userRoute -> userHandler "createUser(vo)"
userHandler -> userRepo "reserve username"
userRepo -> eventStoreService "reserve username"
eventStoreService -> eventStoreService "check if username exists"
eventStoreService -> eventStoreService "reserve username"
userHandler -> userDomain ".make(vo)"
userDomain -> userDomain "create user domain entity + userCreatedEvent(who, what)"
userDomain -> userHandler "return (userDomainEntity + userCreatedEvent)"
userHandler -> userRepo "storeUser(userDomainEntity + userCreatedEvent)"
userRepo -> eventStoreService "storeUser(userDomainEntity + userCreatedEvent)"
eventStoreService -> eventStoreService "store event(s), userCreatedEvent(who, what, when(!))"
eventStoreService -> eventListener "publishEvent(userCreatedEvent)"
eventListener -> triplestoreService "writeToTsService(E)"
triplestoreService -> triplestoreService "SPARQL Update"
eventListener -> arkService "writeToArkService(E)"
arkService -> arkService "create ARK(URL)"
eventListener -> elasticSearchService "writeToEsService(E)"

}

dynamic userSlice "HttpRequestWithEventsUpdateUser" "Example workflow for a HTTP request with events (update username)" {
user -> userRoute "sends HTTP request to"
userRoute -> userRoute "validates input and creates value objects"
userRoute -> userHandler "updateUsername(vo)"
userHandler -> userRepo "getUser(userId)"
userRepo -> eventStoreService "getUser(userId)"
eventStoreService -> eventStoreService "get all events for this user"
eventStoreService -> userDomain "createUserFromEvents(E,E,E,...)"
userDomain -> userHandler "return User"
userHandler -> userDomain "updateUsername(vo)"
userDomain -> userDomain "updateUser(userDomainEntity + userUpdatedEvent(who, what))"
userDomain -> userHandler "return userDomainEntity + userUpdatedEvent(who, what)"
userHandler -> userRepo "storeUser(userDomainEntity + userUpdatedEvent(who, what, when(!))"

userRepo -> eventStoreService "storeUser(userDomainEntity + userCreatedEvent)"
eventStoreService -> eventStoreService "store event(s), userCreatedEvent(who, what, when(!))"
eventStoreService -> eventListener "publishEvent(userCreatedEvent)"
eventListener -> triplestoreService "writeToTsService(E)"
triplestoreService -> triplestoreService "SPARQL Update"
eventListener -> arkService "writeToArkService(E)"
arkService -> arkService "create ARK(URL)"
eventListener -> elasticSearchService "writeToEsService(E)"

autoLayout
}

theme default
}

!adrs decisions
!docs flows
!docs docs
}