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

[Feature] Allow admins to create an Organization. #99

Merged
merged 80 commits into from
Dec 3, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
92104e5
updated models
sinamics Aug 22, 2023
6cb3123
new admin menu tab
sinamics Aug 22, 2023
4872fc0
Merge branch 'main' into organization
sinamics Nov 17, 2023
b1f7b4e
org
sinamics Nov 17, 2023
c52ffd8
organization db model
sinamics Nov 18, 2023
ae17ca3
icon
sinamics Nov 18, 2023
97290b3
header
sinamics Nov 18, 2023
14be1b5
nav
sinamics Nov 19, 2023
78ed609
fetch orgs
sinamics Nov 19, 2023
124af6a
socket
sinamics Nov 19, 2023
90ea9e2
Merge branch 'main' into organization
sinamics Nov 19, 2023
1a22fac
trpc wss server
sinamics Nov 19, 2023
6d3cadd
org network
sinamics Nov 24, 2023
2fb757a
websocket
sinamics Nov 24, 2023
52b94f8
update nextjs, next-intl websocket
sinamics Nov 24, 2023
24f908e
change url path
sinamics Nov 24, 2023
653f4f9
positioning
sinamics Nov 24, 2023
d93ca54
removed central beta
sinamics Nov 24, 2023
9a19a84
lint
sinamics Nov 24, 2023
139a6c5
org dashboard
sinamics Nov 24, 2023
ad2ca64
beta note
sinamics Nov 24, 2023
f5c264a
user activity log
sinamics Nov 25, 2023
00796fe
logfooter
sinamics Nov 25, 2023
96b64d6
chat icons
sinamics Nov 25, 2023
d96be6d
user color
sinamics Nov 25, 2023
72cc802
logging
sinamics Nov 25, 2023
4d6abdd
routing
sinamics Nov 26, 2023
f74d432
user invitation
sinamics Nov 26, 2023
7439ef6
email template
sinamics Nov 26, 2023
a522eb4
leave org, modals, invite
sinamics Nov 27, 2023
fe6ea9e
org layout
sinamics Nov 27, 2023
d5ebf56
logging
sinamics Nov 27, 2023
b2c0513
sidebar active tab
sinamics Nov 27, 2023
49e00bc
cascade when deleting a org.
sinamics Nov 27, 2023
c55c196
permissions
sinamics Nov 27, 2023
1aae85c
descption
sinamics Nov 27, 2023
1d2cc70
intl
sinamics Nov 27, 2023
6f5e2da
new build
sinamics Nov 28, 2023
baa5941
update tests
sinamics Nov 28, 2023
a011f05
updated tests
sinamics Nov 28, 2023
d9f076a
test
sinamics Nov 28, 2023
cd6142e
modal
sinamics Nov 28, 2023
bfa817a
layout
sinamics Nov 28, 2023
d8a5d6d
layout
sinamics Nov 30, 2023
02ffb4c
error message
sinamics Nov 30, 2023
4d92507
org meta
sinamics Nov 30, 2023
11a5c6b
org user edit
sinamics Nov 30, 2023
0c820df
org id object
sinamics Nov 30, 2023
6863f7c
add user description
sinamics Nov 30, 2023
649c8d7
msg notification system
sinamics Dec 1, 2023
1d12252
chat
sinamics Dec 1, 2023
4cc69e8
lint
sinamics Dec 1, 2023
6a9e713
remove NEXTAUTH_URL_INTERNAL
sinamics Dec 1, 2023
bf31716
lint
sinamics Dec 1, 2023
e7b98db
docs
sinamics Dec 1, 2023
653ef97
crud network
sinamics Dec 1, 2023
d11ed9b
error handling
sinamics Dec 1, 2023
47f9735
role
sinamics Dec 1, 2023
c4af2d3
permissions
sinamics Dec 1, 2023
49676cf
permissions
sinamics Dec 1, 2023
867fea2
translations
sinamics Dec 1, 2023
40ca267
Merge branch 'main' into organization
sinamics Dec 2, 2023
c4dcb70
biome linting
sinamics Dec 2, 2023
cadc72b
translations
sinamics Dec 2, 2023
faa88cd
translations
sinamics Dec 2, 2023
c12fb92
org form
sinamics Dec 2, 2023
ba922bf
update prisma
sinamics Dec 2, 2023
cc04ab8
translations
sinamics Dec 3, 2023
044c931
translations
sinamics Dec 3, 2023
3f10d54
translations
sinamics Dec 3, 2023
4542468
cascade logs
sinamics Dec 3, 2023
3160911
delete network org id
sinamics Dec 3, 2023
bbfe514
scrollintoView
sinamics Dec 3, 2023
aa4c07f
translations
sinamics Dec 3, 2023
fde58d2
translations
sinamics Dec 3, 2023
9208ff8
translations
sinamics Dec 3, 2023
cad36f0
lint
sinamics Dec 3, 2023
a549bf9
lint
sinamics Dec 3, 2023
fd4378e
translations
sinamics Dec 3, 2023
0d0dedc
translations
sinamics Dec 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 0 additions & 36 deletions prisma/migrations/20230822195235_organization/migration.sql

This file was deleted.

111 changes: 111 additions & 0 deletions prisma/migrations/20231118160452_organization/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
-- AlterTable
ALTER TABLE "network" ADD COLUMN "organizationId" TEXT;

-- CreateTable
CREATE TABLE "Organization" (
"id" TEXT NOT NULL,
"ownerId" TEXT NOT NULL,
"orgName" TEXT NOT NULL,
"description" TEXT,
"isActive" BOOLEAN NOT NULL DEFAULT true,

CONSTRAINT "Organization_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "UserOrganizationRole" (
"userId" TEXT NOT NULL,
"organizationId" TEXT NOT NULL,
"role" "Role" NOT NULL,

CONSTRAINT "UserOrganizationRole_pkey" PRIMARY KEY ("userId","organizationId")
);

-- CreateTable
CREATE TABLE "NetworkAccess" (
"userId" TEXT NOT NULL,
"networkId" TEXT NOT NULL,
"organizationId" TEXT NOT NULL,

CONSTRAINT "NetworkAccess_pkey" PRIMARY KEY ("userId","networkId","organizationId")
);

-- CreateTable
CREATE TABLE "OrganizationSettings" (
"id" SERIAL NOT NULL,
"organizationId" TEXT NOT NULL,

CONSTRAINT "OrganizationSettings_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "OrganizationInvitation" (
"id" SERIAL NOT NULL,
"token" TEXT NOT NULL,
"organizationId" TEXT NOT NULL,

CONSTRAINT "OrganizationInvitation_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "MembershipRequest" (
"id" SERIAL NOT NULL,
"userId" TEXT NOT NULL,
"organizationId" TEXT NOT NULL,

CONSTRAINT "MembershipRequest_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "_MemberRelation" (
"A" TEXT NOT NULL,
"B" TEXT NOT NULL
);

-- CreateIndex
CREATE UNIQUE INDEX "OrganizationSettings_organizationId_key" ON "OrganizationSettings"("organizationId");

-- CreateIndex
CREATE UNIQUE INDEX "OrganizationInvitation_token_key" ON "OrganizationInvitation"("token");

-- CreateIndex
CREATE UNIQUE INDEX "_MemberRelation_AB_unique" ON "_MemberRelation"("A", "B");

-- CreateIndex
CREATE INDEX "_MemberRelation_B_index" ON "_MemberRelation"("B");

-- AddForeignKey
ALTER TABLE "network" ADD CONSTRAINT "network_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "UserOrganizationRole" ADD CONSTRAINT "UserOrganizationRole_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "UserOrganizationRole" ADD CONSTRAINT "UserOrganizationRole_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "NetworkAccess" ADD CONSTRAINT "NetworkAccess_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "NetworkAccess" ADD CONSTRAINT "NetworkAccess_networkId_fkey" FOREIGN KEY ("networkId") REFERENCES "network"("nwid") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "NetworkAccess" ADD CONSTRAINT "NetworkAccess_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "OrganizationSettings" ADD CONSTRAINT "OrganizationSettings_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "OrganizationInvitation" ADD CONSTRAINT "OrganizationInvitation_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "MembershipRequest" ADD CONSTRAINT "MembershipRequest_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "MembershipRequest" ADD CONSTRAINT "MembershipRequest_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "_MemberRelation" ADD CONSTRAINT "_MemberRelation_A_fkey" FOREIGN KEY ("A") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "_MemberRelation" ADD CONSTRAINT "_MemberRelation_B_fkey" FOREIGN KEY ("B") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
129 changes: 94 additions & 35 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ datasource db {
shadowDatabaseUrl = env("MIGRATE_DATABASE_URL")
}

enum Role {
USER
MODERATOR
ADMIN
}

model GlobalOptions {
id Int @id @default(autoincrement())

Expand Down Expand Up @@ -52,11 +58,6 @@ model GlobalOptions {
welcomeMessageBody String?
}

enum Role {
USER
MODERATOR
ADMIN
}

model network_members {
nodeid Int @id @default(autoincrement())
Expand Down Expand Up @@ -86,8 +87,9 @@ model network {
tagsByName Json?
capabilitiesByName Json?

organizationId Int?
organization Organization? @relation(fields: [organizationId], references: [id], onDelete: SetNull)
organizationId String?
organization Organization? @relation(fields: [organizationId], references: [id], onDelete: SetNull)
networkAccesses NetworkAccess[]

networkMembers network_members[]
notations Notation[]
Expand Down Expand Up @@ -191,48 +193,42 @@ model APIToken {
}

model User {
id String @id @default(cuid())
id String @id @default(cuid())
name String
email String @unique
email String @unique
emailVerified DateTime?
lastLogin DateTime
lastseen DateTime?
expirationDate String @default("")
online Boolean? @default(false)
role Role @default(USER)
expirationDate String @default("")
online Boolean? @default(false)
role Role @default(USER)
image String?
hash String
licenseStatus String?
orderStatus String?
orderId Int @default(0)
product_id Int? @default(0)
licenseKey String? @default("")
orderId Int @default(0)
product_id Int? @default(0)
licenseKey String? @default("")
tempPassword String?
firstTime Boolean @default(true)
firstTime Boolean @default(true)
userGroupId Int?

adminOrgs Organization[] @relation("AdminRelation")
organizations Organization[] @relation("MemberRelation")
memberOfOrgs Organization[] @relation("MemberRelation") // user can be member of multiple organizations
organizationRoles UserOrganizationRole[]
membershipRequests MembershipRequest[] @relation("MembershipRequestsForUser")
networkAccesses NetworkAccess[]
expiresAt DateTime? // null means it never expires
isActive Boolean @default(true)

userGroup UserGroup? @relation(fields: [userGroupId], references: [id], onDelete: Restrict)
options UserOptions?
accounts Account[]
sessions Session[]
network network[]
apiTokens APIToken[]
isActive Boolean @default(true)

userGroup UserGroup? @relation(fields: [userGroupId], references: [id], onDelete: Restrict)
options UserOptions?
accounts Account[]
sessions Session[]
network network[]
apiTokens APIToken[]
}

model Organization {
id Int @id @default(autoincrement())
name String
description String?
adminId String
admin User @relation("AdminRelation", fields: [adminId], references: [id])
members User[] @relation("MemberRelation")
networks network[]
}


model VerificationToken {
identifier String
Expand All @@ -257,6 +253,69 @@ model UserInvitation {
}


//
// ORGANIZATION
//

model Organization {
id String @id @default(cuid())
ownerId String
orgName String
description String?
users User[] @relation("MemberRelation")
networks network[]
settings OrganizationSettings?
invitations OrganizationInvitation[]
membershipRequests MembershipRequest[] @relation("MembershipRequestsForOrganization")
isActive Boolean @default(true)
userRoles UserOrganizationRole[]
networkAccesses NetworkAccess[]
}

model UserOrganizationRole {
userId String
organizationId String
role Role
user User @relation(fields: [userId], references: [id])
organization Organization @relation(fields: [organizationId], references: [id])

@@id([userId, organizationId])
}

model NetworkAccess {
userId String
networkId String
organizationId String
user User @relation(fields: [userId], references: [id])
network network @relation(fields: [networkId], references: [nwid])
organization Organization @relation(fields: [organizationId], references: [id])

@@id([userId, networkId, organizationId])
}

model OrganizationSettings {
id Int @id @default(autoincrement())
organizationId String @unique
organization Organization @relation(fields: [organizationId], references: [id])
// Add specific settings fields here
}

model OrganizationInvitation {
id Int @id @default(autoincrement())
token String @unique
organizationId String
organization Organization @relation(fields: [organizationId], references: [id])
}

model MembershipRequest {
id Int @id @default(autoincrement())
userId String
organizationId String
user User @relation(fields: [userId], references: [id], name: "MembershipRequestsForUser")
organization Organization @relation(fields: [organizationId], references: [id], name: "MembershipRequestsForOrganization")
}


// To map your data model to the database schema, you need to use the prisma migrate CLI commands:
// npx prisma migrate dev --name (NAME)

Expand Down
40 changes: 39 additions & 1 deletion src/components/layouts/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ const Sidebar = (): JSX.Element => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [isBelowMd, open, setOpenState, sidebarRef]);

return (
<aside
ref={sidebarRef}
Expand Down Expand Up @@ -121,6 +120,45 @@ const Sidebar = (): JSX.Element => {
<span className="ml-3">{t("networks")}</span>
</Link>
</li>
{me?.memberOfOrgs?.length > 0 ? (
<>
<li className="my-px">
<span className="my-4 flex px-4 text-sm font-medium uppercase text-primary">
Organiszation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean "Organization"? :)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but these hardcoded text is just kinda placeholders. All text will be added to the translation files later with correct spelling. :)

</span>
</li>
{me?.memberOfOrgs.map((org) => (
<li key={org.orgName} className="my-px">
<Link
href={`/organization/${org.orgName}`}
className={`flex h-10 flex-row items-center rounded-lg px-3
${
router.pathname.includes("/network")
? "bg-gray-100 text-gray-700"
: "hover:bg-slate-700"
}`}
>
<span className="flex items-center justify-center text-lg text-gray-400">
{/* https://heroicons.com/ */}
<svg
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
stroke="currentColor"
className="h-6 w-6"
>
<path d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4" />
</svg>
</span>
<span className="ml-3">{org.orgName}</span>
</Link>
</li>
))}
</>
) : null}

{me?.options?.ztCentralApiKey ? (
<li className="my-px">
<Link
Expand Down
2 changes: 1 addition & 1 deletion src/components/networkByIdPage/organization/addOrgForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const AddOrgForm = () => {
refetch();
},
});

// console.log(userOrgs);
return (
<div className="space-y-10">
<div className="pb-5">
Expand Down
Loading
Loading