Skip to content

Commit d0931dc

Browse files
committed
feat: eVoting group thing done
1 parent 0e44738 commit d0931dc

File tree

14 files changed

+772
-121
lines changed

14 files changed

+772
-121
lines changed
304 KB
Binary file not shown.

infrastructure/web3-adapter/src/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,13 @@ export class Web3Adapter {
305305
);
306306

307307
if (!this.mapping[tableName]) return;
308+
309+
if (this.mapping[tableName].readOnly) {
310+
// early return on mappings which are readonly so as to not
311+
// sync any update to the eVault which is not warranted
312+
return;
313+
}
314+
308315
console.log("We get here?");
309316
// If we already have a mapping, use that global ID
310317

infrastructure/web3-adapter/src/mapper/mapper.types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ export interface IMapping {
3333
* String to String mapping between what path maps to what global ontology
3434
*/
3535
localToUniversalMap: Record<string, string>;
36+
37+
/**
38+
* If true, this mapping will not trigger handleChange and will be treated as read-only.
39+
* Useful for entities that should not be synced to eVaults.
40+
*/
41+
readOnly?: boolean;
3642
}
3743

3844
export interface IMappingConversionOptions {

platforms/cerberus/src/web3adapter/mappings/group.mapping.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@
1212
"participants": "users(participants[].id),participantIds",
1313
"createdAt": "createdAt",
1414
"updatedAt": "updatedAt"
15-
}
15+
},
16+
"readOnly": true
1617
}

platforms/cerberus/src/web3adapter/mappings/user.mapping.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@
1717
"isArchived": "isArchived",
1818
"followers": "followers",
1919
"following": "following"
20-
}
20+
},
21+
"readOnly": true
2122
}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import { Request, Response } from "express";
2+
import { GroupService } from "../services/GroupService";
3+
import { AppDataSource } from "../database/data-source";
4+
import { User } from "../database/entities/User";
5+
6+
export class GroupController {
7+
private groupService: GroupService;
8+
private userRepository = AppDataSource.getRepository(User);
9+
10+
constructor() {
11+
this.groupService = new GroupService();
12+
}
13+
14+
// Create a new group
15+
createGroup = async (req: Request, res: Response) => {
16+
try {
17+
const { name, description, memberIds, adminIds, isPrivate, visibility, avatarUrl, bannerUrl } = req.body;
18+
19+
if (!name) {
20+
return res.status(400).json({ error: "Group name is required" });
21+
}
22+
23+
const group = await this.groupService.createGroup(
24+
name,
25+
description,
26+
memberIds || [],
27+
adminIds || [],
28+
isPrivate || false,
29+
visibility || "public",
30+
avatarUrl,
31+
bannerUrl
32+
);
33+
34+
res.status(201).json(group);
35+
} catch (error) {
36+
console.error("Error creating group:", error);
37+
res.status(500).json({ error: "Failed to create group" });
38+
}
39+
};
40+
41+
// Get group by ID
42+
getGroupById = async (req: Request, res: Response) => {
43+
try {
44+
const { id } = req.params;
45+
const group = await this.groupService.getGroupById(id);
46+
47+
if (!group) {
48+
return res.status(404).json({ error: "Group not found" });
49+
}
50+
51+
res.json(group);
52+
} catch (error) {
53+
console.error("Error getting group:", error);
54+
res.status(500).json({ error: "Failed to get group" });
55+
}
56+
};
57+
58+
// Update group
59+
updateGroup = async (req: Request, res: Response) => {
60+
try {
61+
const { id } = req.params;
62+
const updates = req.body;
63+
64+
const group = await this.groupService.updateGroup(id, updates);
65+
res.json(group);
66+
} catch (error) {
67+
console.error("Error updating group:", error);
68+
res.status(500).json({ error: "Failed to update group" });
69+
}
70+
};
71+
72+
// Delete group
73+
deleteGroup = async (req: Request, res: Response) => {
74+
try {
75+
const { id } = req.params;
76+
await this.groupService.deleteGroup(id);
77+
res.status(204).send();
78+
} catch (error) {
79+
console.error("Error deleting group:", error);
80+
res.status(500).json({ error: "Failed to delete group" });
81+
}
82+
};
83+
84+
// Get user's groups
85+
getUserGroups = async (req: Request, res: Response) => {
86+
try {
87+
const { userId } = req.params;
88+
const { page = 1, limit = 10 } = req.query;
89+
90+
const result = await this.groupService.getUserGroups(
91+
userId,
92+
parseInt(page as string),
93+
parseInt(limit as string)
94+
);
95+
96+
res.json(result);
97+
} catch (error) {
98+
console.error("Error getting user groups:", error);
99+
res.status(500).json({ error: "Failed to get user groups" });
100+
}
101+
};
102+
103+
// Add members to group
104+
addMembers = async (req: Request, res: Response) => {
105+
try {
106+
const { id } = req.params;
107+
const { memberIds } = req.body;
108+
109+
if (!Array.isArray(memberIds)) {
110+
return res.status(400).json({ error: "memberIds must be an array" });
111+
}
112+
113+
const group = await this.groupService.addMembers(id, memberIds);
114+
res.json(group);
115+
} catch (error) {
116+
console.error("Error adding members:", error);
117+
res.status(500).json({ error: "Failed to add members" });
118+
}
119+
};
120+
121+
// Remove member from group
122+
removeMember = async (req: Request, res: Response) => {
123+
try {
124+
const { id, userId } = req.params;
125+
const group = await this.groupService.removeMember(id, userId);
126+
res.json(group);
127+
} catch (error) {
128+
console.error("Error removing member:", error);
129+
res.status(500).json({ error: "Failed to remove member" });
130+
}
131+
};
132+
133+
// Add admins to group
134+
addAdmins = async (req: Request, res: Response) => {
135+
try {
136+
const { id } = req.params;
137+
const { adminIds } = req.body;
138+
139+
if (!Array.isArray(adminIds)) {
140+
return res.status(400).json({ error: "adminIds must be an array" });
141+
}
142+
143+
const group = await this.groupService.addAdmins(id, adminIds);
144+
res.json(group);
145+
} catch (error) {
146+
console.error("Error adding admins:", error);
147+
res.status(500).json({ error: "Failed to add admins" });
148+
}
149+
};
150+
151+
// Remove admin from group
152+
removeAdmin = async (req: Request, res: Response) => {
153+
try {
154+
const { id, userId } = req.params;
155+
const group = await this.groupService.removeAdmin(id, userId);
156+
res.json(group);
157+
} catch (error) {
158+
console.error("Error removing admin:", error);
159+
res.status(500).json({ error: "Failed to remove admin" });
160+
}
161+
};
162+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import {
2+
Entity,
3+
CreateDateColumn,
4+
UpdateDateColumn,
5+
PrimaryGeneratedColumn,
6+
Column,
7+
ManyToMany,
8+
JoinTable,
9+
} from "typeorm";
10+
import { User } from "./User";
11+
12+
@Entity()
13+
export class Group {
14+
@PrimaryGeneratedColumn("uuid")
15+
id!: string;
16+
17+
@Column({ nullable: true })
18+
name!: string;
19+
20+
@Column({ nullable: true })
21+
description!: string;
22+
23+
@Column({ nullable: true })
24+
owner!: string;
25+
26+
@Column("simple-array", { nullable: true })
27+
admins!: string[];
28+
29+
@Column({ type: "text", nullable: true })
30+
charter!: string; // Markdown content for the group charter
31+
32+
@Column({ default: false })
33+
isPrivate!: boolean;
34+
35+
@Column({ default: "public" })
36+
visibility!: "public" | "private" | "restricted";
37+
38+
@ManyToMany(() => User)
39+
@JoinTable({
40+
name: "group_members",
41+
joinColumn: { name: "group_id", referencedColumnName: "id" },
42+
inverseJoinColumn: { name: "user_id", referencedColumnName: "id" }
43+
})
44+
members!: User[];
45+
46+
@ManyToMany(() => User)
47+
@JoinTable({
48+
name: "group_participants",
49+
joinColumn: { name: "group_id", referencedColumnName: "id" },
50+
inverseJoinColumn: { name: "user_id", referencedColumnName: "id" }
51+
})
52+
participants!: User[];
53+
54+
@Column({ nullable: true })
55+
avatarUrl!: string;
56+
57+
@Column({ nullable: true })
58+
bannerUrl!: string;
59+
60+
@CreateDateColumn()
61+
createdAt!: Date;
62+
63+
@UpdateDateColumn()
64+
updatedAt!: Date;
65+
}

platforms/evoting-api/src/database/entities/User.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import {
55
CreateDateColumn,
66
UpdateDateColumn,
77
OneToMany,
8+
ManyToMany,
9+
JoinTable,
810
} from "typeorm";
911
import { Poll } from "./Poll";
1012
import { Vote } from "./Vote";
@@ -50,6 +52,22 @@ export class User {
5052
@OneToMany(() => Vote, (vote) => vote.user)
5153
votes!: Vote[];
5254

55+
@ManyToMany(() => User)
56+
@JoinTable({
57+
name: "user_followers",
58+
joinColumn: { name: "user_id", referencedColumnName: "id" },
59+
inverseJoinColumn: { name: "follower_id", referencedColumnName: "id" },
60+
})
61+
followers!: User[];
62+
63+
@ManyToMany(() => User)
64+
@JoinTable({
65+
name: "user_following",
66+
joinColumn: { name: "user_id", referencedColumnName: "id" },
67+
inverseJoinColumn: { name: "following_id", referencedColumnName: "id" },
68+
})
69+
following!: User[];
70+
5371
@CreateDateColumn()
5472
createdAt!: Date;
5573

0 commit comments

Comments
 (0)