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

Group management #106

Merged
merged 11 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
108 changes: 108 additions & 0 deletions functions/src/database/groups/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/***********************************************************************************************
* Nonprofit Social Networking Platform: Allowing Users and Organizations to Collaborate.
* Copyright (C) 2023 ASCENDynamics NFP
*
* This file is part of Nonprofit Social Networking Platform.
*
* Nonprofit Social Networking Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.

* Nonprofit Social Networking Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.

* You should have received a copy of the GNU Affero General Public License
* along with Nonprofit Social Networking Platform. If not, see <https://www.gnu.org/licenses/>.
***********************************************************************************************/
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import * as logger from "firebase-functions/logger";

const db = admin.firestore();

export const onGroupCreation = functions.firestore
.document("groups/{groupId}")
.onCreate(handleGroupCreation);

/**
* Asynchronously handles the creation of groups in the database.
* This function logs the group creation, and depending on the status of the new group,
* creates a corresponding relationship in the database.
* @param {Object} snapshot - The snapshot of the group document that was created.
* @param {Object} context - The context in which the function is run, including event context.
* @return {Promise<void>} - Returns a promise that resolves when the operation is complete
*/
async function handleGroupCreation(snapshot: any, context: any) {
logger.info("snapshot: ", snapshot);
logger.info("context: ", context);
const newGroup = snapshot.data();
if (newGroup) {
logger.info("newGroup: ", newGroup);
// Use a transaction to ensure atomic update
return db
.runTransaction(async (transaction) => {
const userDataSnapshot = await fetchUser(
transaction,
newGroup.createdBy,
);
logger.info("userDataSnapshot: ", userDataSnapshot);
if (userDataSnapshot.exists) {
const userData = userDataSnapshot.data();
logger.info("userData: ", userData);
const relationshipData = {
createdAt: admin.firestore.FieldValue.serverTimestamp(),
createdBy: newGroup.createdBy,
id: null,
senderId: newGroup.createdBy,
receiverId: context.params.groupId,
type: "member",
status: "accepted",
membershipRole: "admin",
receiverRelationship: "group",
senderRelationship: "user",
senderName: userData?.displayName, // Assuming the user data has a 'displayName' field
senderImage: userData?.profilePicture, // Assuming the user data has an 'profilePicture' field
senderTagline: userData?.tagline, // Assuming the user data has a 'tagline' field
receiverName: newGroup.name, // Assuming the group data has a 'name' field
receiverImage: newGroup.logoImage, // Assuming the group data has an 'logoImage' field
receiverTagline: newGroup.tagline, // Assuming the group data has a 'tagline' field
lastModifiedAt: admin.firestore.FieldValue.serverTimestamp(),
lastModifiedBy: newGroup.createdBy,
};

await transaction.set(
db.collection("relationships").doc(),
relationshipData,
);
}
})
.catch((error) => {
logger.error("Transaction failed: ", error);
throw error;
});
}
}

/**
* Fetches a user document based on the provided userId
* @param {admin.firestore.Transaction} transaction - The Firestore transaction
* @param {string} userId - The ID of the user to fetch
* @return {Promise<admin.firestore.DocumentSnapshot>} A promise that resolves with the fetched user document
*/
async function fetchUser(
transaction: admin.firestore.Transaction,
userId: string,
) {
const userRef = db.collection("users").doc(userId);
const userDoc = await transaction.get(userRef);

if (!userDoc.exists) {
logger.error("User not found");
throw new Error("User not found");
}

return userDoc;
}
19 changes: 19 additions & 0 deletions functions/src/database/relationships/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
/***********************************************************************************************
* Nonprofit Social Networking Platform: Allowing Users and Organizations to Collaborate.
* Copyright (C) 2023 ASCENDynamics NFP
*
* This file is part of Nonprofit Social Networking Platform.
*
* Nonprofit Social Networking Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.

* Nonprofit Social Networking Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.

* You should have received a copy of the GNU Affero General Public License
* along with Nonprofit Social Networking Platform. If not, see <https://www.gnu.org/licenses/>.
***********************************************************************************************/
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import * as logger from "firebase-functions/logger";
Expand Down
29 changes: 22 additions & 7 deletions functions/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
/***********************************************************************************************
* Nonprofit Social Networking Platform: Allowing Users and Organizations to Collaborate.
* Copyright (C) 2023 ASCENDynamics NFP
*
* This file is part of Nonprofit Social Networking Platform.
*
* Nonprofit Social Networking Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.

* Nonprofit Social Networking Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.

* You should have received a copy of the GNU Affero General Public License
* along with Nonprofit Social Networking Platform. If not, see <https://www.gnu.org/licenses/>.
***********************************************************************************************/

/**
* Import function triggers from their respective submodules:
*
Expand All @@ -17,10 +37,5 @@
// logger.info("Hello logs!", {structuredData: true});
// response.send("Hello from Firebase!");
// });
import {
onRelationshipCreation,
onRelationshipDeletion,
onRelationshipUpdate,
} from "./database/relationships"; // relationships triggers

export {onRelationshipCreation, onRelationshipDeletion, onRelationshipUpdate}; // relationships triggers
export * from "./database/relationships"; // triggers
export * from "./database/groups"; // triggers
11 changes: 9 additions & 2 deletions src/app/core/services/groups.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,19 @@ export class GroupsService {
private successHandler: SuccessHandlerService,
) {}

async createGroup(group: AppGroup): Promise<string | null> {
async createGroup(group: Partial<AppGroup>): Promise<string | null> {
const loading = await this.loadingController.create();
await loading.present();
const userId = this.authService.getCurrentUser()?.uid;
if (userId) {
group.admins = [userId];
group.members = [userId];
}
group.logoImage = "assets/icon/favicon.png";
group.heroImage = "assets/image/orghero.png";
return await addDoc(
collection(this.firestoreService.firestore, this.collectionName),
prepareDataForCreate(group, this.authService.getCurrentUser()?.uid),
prepareDataForCreate(group, userId),
)
.then((docRef) => {
this.successHandler.handleSuccess("Request sent successfully!");
Expand Down
1 change: 1 addition & 0 deletions src/app/models/user.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export interface AppUser {
email: string; // Email address
emailVerified: boolean; // Whether the user's email is verified
name: string; // First and last name
heroImage: string; // base64 string
profilePicture: string; // base64 string
dateOfBirth: Timestamp; // Birthday
language: string; // User's language
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<!--
Nonprofit Social Networking Platform: Allowing Users and Organizations to Collaborate.
Copyright (C) 2023 ASCENDynamics NFP

This file is part of Nonprofit Social Networking Platform.

Nonprofit Social Networking Platform is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Nonprofit Social Networking Platform is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with Nonprofit Social Networking Platform. If not, see <https://www.gnu.org/licenses/>.
-->
<ion-header>
<ion-toolbar>
<ion-title>Create New Group</ion-title>
<ion-buttons slot="end">
<ion-button (click)="cancel()">Close</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>

<ion-content>
<form [formGroup]="groupForm" (ngSubmit)="onSubmit()">
<ion-item>
<ion-label position="stacked"
>Group Name <ion-text color="danger">*</ion-text></ion-label
>
<ion-input type="text" formControlName="name"></ion-input>
</ion-item>

<ion-item>
<ion-label position="stacked"
>Group Description <ion-text color="danger">*</ion-text></ion-label
>
<ion-textarea formControlName="description"></ion-textarea>
</ion-item>

<ion-item>
<ion-label position="stacked"
>Group Tagline <ion-text color="danger">*</ion-text></ion-label
>
<ion-input type="text" formControlName="tagline"></ion-input>
</ion-item>

<ion-button expand="full" type="submit" [disabled]="groupForm.invalid">
Create Group
</ion-button>
</form>
</ion-content>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/***********************************************************************************************
* Nonprofit Social Networking Platform: Allowing Users and Organizations to Collaborate.
* Copyright (C) 2023 ASCENDynamics NFP
*
* This file is part of Nonprofit Social Networking Platform.
*
* Nonprofit Social Networking Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.

* Nonprofit Social Networking Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.

* You should have received a copy of the GNU Affero General Public License
* along with Nonprofit Social Networking Platform. If not, see <https://www.gnu.org/licenses/>.
***********************************************************************************************/
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/***********************************************************************************************
* Nonprofit Social Networking Platform: Allowing Users and Organizations to Collaborate.
* Copyright (C) 2023 ASCENDynamics NFP
*
* This file is part of Nonprofit Social Networking Platform.
*
* Nonprofit Social Networking Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.

* Nonprofit Social Networking Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.

* You should have received a copy of the GNU Affero General Public License
* along with Nonprofit Social Networking Platform. If not, see <https://www.gnu.org/licenses/>.
***********************************************************************************************/
import {ComponentFixture, TestBed, waitForAsync} from "@angular/core/testing";
import {IonicModule} from "@ionic/angular";

import {CreateGroupModalComponent} from "./create-group-modal.component";

describe("CreateGroupModalComponent", () => {
let component: CreateGroupModalComponent;
let fixture: ComponentFixture<CreateGroupModalComponent>;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [IonicModule.forRoot()],
}).compileComponents();

fixture = TestBed.createComponent(CreateGroupModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));

it("should create", () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/***********************************************************************************************
* Nonprofit Social Networking Platform: Allowing Users and Organizations to Collaborate.
* Copyright (C) 2023 ASCENDynamics NFP
*
* This file is part of Nonprofit Social Networking Platform.
*
* Nonprofit Social Networking Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.

* Nonprofit Social Networking Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.

* You should have received a copy of the GNU Affero General Public License
* along with Nonprofit Social Networking Platform. If not, see <https://www.gnu.org/licenses/>.
***********************************************************************************************/
import {Component} from "@angular/core";
import {IonicModule, ModalController} from "@ionic/angular";
import {CommonModule} from "@angular/common";
import {
FormBuilder,
FormsModule,
ReactiveFormsModule,
Validators,
} from "@angular/forms";
import {GroupsService} from "../../../../core/services/groups.service";
import {AppGroup} from "../../../../models/group.model";

@Component({
selector: "app-create-group-modal",
templateUrl: "./create-group-modal.component.html",
styleUrls: ["./create-group-modal.component.scss"],
standalone: true,
imports: [CommonModule, IonicModule, FormsModule, ReactiveFormsModule],
})
export class CreateGroupModalComponent {
groupForm = this.fb.group({
name: ["", Validators.required],
description: ["", Validators.required],
tagline: ["", Validators.required],
});

constructor(
private modalCtrl: ModalController,
private fb: FormBuilder,
private groupsService: GroupsService,
) {}

cancel() {
return this.modalCtrl.dismiss(null, "cancel");
}

confirm() {
return this.modalCtrl.dismiss(null, "confirm");
}

onSubmit() {
this.groupsService
.createGroup(this.groupForm.value as Partial<AppGroup>)
.then((groupId) => {
return this.modalCtrl.dismiss({groupId: groupId}, "confirm");
});
}
}
4 changes: 2 additions & 2 deletions src/app/modules/group/pages/group-list/group-list.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@
>
<ion-thumbnail slot="start">
<img
*ngIf="item.groupPicture"
*ngIf="item.logoImage"
[alt]="item.name"
[src]="item.groupPicture"
[src]="item.logoImage"
/>
</ion-thumbnail>
<ion-label>
Expand Down
Loading
Loading