Abdul Rehman commited on
Commit
644d830
·
1 Parent(s): d60fe6f

tracking code

Browse files
src/app.module.ts CHANGED
@@ -4,13 +4,10 @@ import { AppService } from './app.service';
4
  import { PropertyModule } from './modules/property/property.module';
5
  import { AuthModule } from './modules/auth/auth.module';
6
  import { UserModule } from './modules/user/user.module';
 
7
 
8
  @Module({
9
- imports: [
10
- PropertyModule,
11
- AuthModule,
12
- UserModule,
13
- ],
14
  controllers: [AppController],
15
  providers: [AppService],
16
  })
 
4
  import { PropertyModule } from './modules/property/property.module';
5
  import { AuthModule } from './modules/auth/auth.module';
6
  import { UserModule } from './modules/user/user.module';
7
+ import { ActivityModule } from './modules/activity/activity.module';
8
 
9
  @Module({
10
+ imports: [PropertyModule, AuthModule, UserModule, ActivityModule],
 
 
 
 
11
  controllers: [AppController],
12
  providers: [AppService],
13
  })
src/constants/collections.constant.ts CHANGED
@@ -1,2 +1,3 @@
1
  export const PROPERTIE = 'propertie';
2
  export const USERS = 'users';
 
 
1
  export const PROPERTIE = 'propertie';
2
  export const USERS = 'users';
3
+ export const ACTIVITY = 'activity';
src/constants/repository.constant.ts CHANGED
@@ -1,2 +1,3 @@
1
  export const PROPERTY_REPOSITORY = 'PROPERTY_REPOSITORY';
2
  export const USER_REPOSITORY = 'USER_REPOSITORY';
 
 
1
  export const PROPERTY_REPOSITORY = 'PROPERTY_REPOSITORY';
2
  export const USER_REPOSITORY = 'USER_REPOSITORY';
3
+ export const ACTIVITY_REPOSITORY = 'ACTIVITY_REPOSITORY';
src/modules/activity/activity.controller.ts ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ Body,
3
+ Controller,
4
+ Get,
5
+ HttpStatus,
6
+ Patch,
7
+ Post,
8
+ Query,
9
+ Req,
10
+ Res,
11
+ UseGuards,
12
+ } from '@nestjs/common';
13
+ import { Response } from 'express';
14
+ import { CommonServices } from '../shared/common.service';
15
+ import { ActivityService } from './activity.service';
16
+ import { JwtAuthGuard } from '../auth/jwt-auth.guard';
17
+ import { PropertyService } from '../property/property.service';
18
+
19
+ @Controller('activity')
20
+ export class ActivityController extends CommonServices {
21
+ constructor(
22
+ private readonly activityService: ActivityService,
23
+ private readonly propertyService: PropertyService,
24
+ ) {
25
+ super();
26
+ }
27
+
28
+ @Post('create')
29
+ @UseGuards(JwtAuthGuard)
30
+ async createActivity(@Body() body: any, @Res() res: Response, @Req() req) {
31
+ try {
32
+ const payload = {
33
+ ...body,
34
+ userId: req.user.userId,
35
+ };
36
+ const activity = await this.activityService.sharedCreate(payload);
37
+
38
+ // update views
39
+ if (body.action == 'view')
40
+ await this.propertyService.sharedFindOneAndUpdate(
41
+ { _id: body.propertyId },
42
+ {
43
+ $inc: { views: 1 }, // Increment views and add duration
44
+ },
45
+ {},
46
+ );
47
+
48
+ //update duration/ time spend
49
+ if (body.action == 'time_spent')
50
+ await this.propertyService.sharedFindOneAndUpdate(
51
+ { _id: body.propertyId },
52
+ {
53
+ $inc: { total_time_spent: body.duration || 0 }, // Increment views and add duration
54
+ },
55
+ {},
56
+ );
57
+
58
+ return this.sendResponse(
59
+ this.messages.Success,
60
+ activity,
61
+ HttpStatus.OK,
62
+ res,
63
+ );
64
+ } catch (error) {
65
+ console.log(error);
66
+ return this.sendResponse(
67
+ 'Error',
68
+ {},
69
+ HttpStatus.INTERNAL_SERVER_ERROR,
70
+ res,
71
+ );
72
+ }
73
+ }
74
+
75
+ @Get('')
76
+ async getActivityListings(@Res() res: Response, @Req() req): Promise<any> {
77
+ try {
78
+ const response = await this.activityService.sharedFind({});
79
+ return this.sendResponse(
80
+ this.messages.Success,
81
+ response,
82
+ HttpStatus.OK,
83
+ res,
84
+ );
85
+ } catch (error) {
86
+ return this.sendResponse(
87
+ 'Internal server Error',
88
+ {},
89
+ HttpStatus.INTERNAL_SERVER_ERROR,
90
+ res,
91
+ );
92
+ }
93
+ }
94
+
95
+ // New Update API to modify existing activity
96
+ @Patch('update')
97
+ @UseGuards(JwtAuthGuard)
98
+ async updateActivity(
99
+ @Body() body: any, // should include { userId, propertyId, action, duration (optional) }
100
+ @Res() res: Response,
101
+ @Req() req,
102
+ ) {
103
+ try {
104
+ // Check if the activity exists for the user and property
105
+ const existingActivity = await this.activityService.sharedFindOne({
106
+ userId: body.userId,
107
+ propertyId: body.propertyId,
108
+ action: body.action, // Example: 'click' or 'view'
109
+ });
110
+
111
+ if (existingActivity) {
112
+ // If activity exists, update it
113
+ const updatedActivity = await this.activityService.sharedUpdate(
114
+ { _id: existingActivity._id },
115
+ {
116
+ duration: body.duration ? body.duration : existingActivity.duration,
117
+ timestamp: new Date(), // update the timestamp to the latest interaction
118
+ },
119
+ );
120
+
121
+ return this.sendResponse(
122
+ this.messages.Success,
123
+ updatedActivity,
124
+ HttpStatus.OK,
125
+ res,
126
+ );
127
+ } else {
128
+ // If no activity exists, return a not found response
129
+ return this.sendResponse(
130
+ 'Activity not found',
131
+ {},
132
+ HttpStatus.NOT_FOUND,
133
+ res,
134
+ );
135
+ }
136
+ } catch (error) {
137
+ return this.sendResponse(
138
+ 'Internal server Error',
139
+ {},
140
+ HttpStatus.INTERNAL_SERVER_ERROR,
141
+ res,
142
+ );
143
+ }
144
+ }
145
+ }
src/modules/activity/activity.module.ts ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Module } from '@nestjs/common';
2
+ import { DatabaseModule } from '../database/database.module';
3
+ import { ActivityController } from './activity.controller';
4
+ import { ActivityService } from './activity.service';
5
+ import { PropertyService } from '../property/property.service';
6
+
7
+ @Module({
8
+ imports: [DatabaseModule],
9
+ controllers: [ActivityController],
10
+ providers: [ActivityService, PropertyService],
11
+ exports: [ActivityService, PropertyService],
12
+ })
13
+ export class ActivityModule {}
src/modules/activity/activity.provider.ts ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Connection } from 'mongoose';
2
+ import { ACTIVITY, ACTIVITY_REPOSITORY } from 'src/constants';
3
+ import { UserActivitySchema } from './activity.schema';
4
+
5
+ export const activityProviders = [
6
+ {
7
+ provide: ACTIVITY_REPOSITORY,
8
+ useFactory: (connection: Connection) =>
9
+ connection.model(ACTIVITY, UserActivitySchema),
10
+ inject: ['DATABASE_CONNECTION'],
11
+ },
12
+ ];
src/modules/activity/activity.schema.ts ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as mongoose from 'mongoose';
2
+ import { Document } from 'mongoose';
3
+ import { IUserDocument } from '../user/user.schema';
4
+ import { IPropertyDocument } from '../property/property.schema';
5
+
6
+ export interface IUserActivityDocument extends Document {
7
+ userId: IUserDocument;
8
+ propertyId: IPropertyDocument;
9
+ action: string; // E.g., 'click', 'view', 'time_spent'
10
+ timestamp: Date;
11
+ duration?: number; // Store time spent in seconds for 'time_spent' action
12
+ }
13
+
14
+ const UserActivitySchema = new mongoose.Schema<IUserActivityDocument>(
15
+ {
16
+ userId: {
17
+ type: mongoose.Schema.Types.ObjectId,
18
+ ref: 'User',
19
+ required: true,
20
+ },
21
+ propertyId: {
22
+ type: mongoose.Schema.Types.ObjectId,
23
+ ref: 'propertie',
24
+ required: true,
25
+ },
26
+ action: { type: String, required: true }, // 'click', 'view', 'time_spent'
27
+ timestamp: { type: Date, default: Date.now },
28
+ duration: { type: Number }, // Only applicable for 'time_spent'
29
+ },
30
+ {
31
+ toJSON: { versionKey: false },
32
+ },
33
+ );
34
+
35
+ export { UserActivitySchema };
src/modules/activity/activity.service.ts ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Inject, Injectable } from '@nestjs/common';
2
+ import { Model, Types } from 'mongoose';
3
+ import { sharedCrudService } from '../shared/sharedCrud.services';
4
+ import { ACTIVITY_REPOSITORY } from 'src/constants';
5
+ import { IUserActivityDocument } from './activity.schema';
6
+
7
+ @Injectable()
8
+ export class ActivityService extends sharedCrudService {
9
+ constructor(
10
+ @Inject(ACTIVITY_REPOSITORY)
11
+ readonly activityRepository: Model<IUserActivityDocument>,
12
+ ) {
13
+ super(activityRepository);
14
+ }
15
+
16
+ async activityLisitng(
17
+ page: number,
18
+ resPerPage: number,
19
+ search: string,
20
+ ): Promise<any> {
21
+ return 'Hello from Activity service.'
22
+ }
23
+ }
src/modules/database/database.module.ts CHANGED
@@ -2,9 +2,20 @@ import { Module } from '@nestjs/common';
2
  import { databaseProviders } from './database.provider';
3
  import { propertyProviders } from '../property/property.provider';
4
  import { usersProviders } from '../user/user.provider';
 
5
 
6
  @Module({
7
- providers: [...databaseProviders, ...propertyProviders, ...usersProviders],
8
- exports: [...databaseProviders, ...propertyProviders, ...usersProviders],
 
 
 
 
 
 
 
 
 
 
9
  })
10
  export class DatabaseModule {}
 
2
  import { databaseProviders } from './database.provider';
3
  import { propertyProviders } from '../property/property.provider';
4
  import { usersProviders } from '../user/user.provider';
5
+ import { activityProviders } from '../activity/activity.provider';
6
 
7
  @Module({
8
+ providers: [
9
+ ...databaseProviders,
10
+ ...propertyProviders,
11
+ ...usersProviders,
12
+ ...activityProviders,
13
+ ],
14
+ exports: [
15
+ ...databaseProviders,
16
+ ...propertyProviders,
17
+ ...usersProviders,
18
+ ...activityProviders,
19
+ ],
20
  })
21
  export class DatabaseModule {}
src/modules/property/property.schema.ts CHANGED
@@ -10,6 +10,8 @@ export interface IPropertyDocument extends Document {
10
  features?: object;
11
  thumbnail_summary?: string;
12
  listing_url?: string;
 
 
13
  createdAt?: Date;
14
  updatedAt?: Date;
15
  }
@@ -23,6 +25,8 @@ const PropertySchema = new mongoose.Schema<IPropertyDocument>(
23
  features: { type: Object },
24
  listing_url: { type: String },
25
  imgs: [],
 
 
26
  createdAt: { type: Date, default: Date.now },
27
  updatedAt: { type: Date, default: Date.now },
28
  },
 
10
  features?: object;
11
  thumbnail_summary?: string;
12
  listing_url?: string;
13
+ views?: number; // Track the number of views
14
+ total_time_spent?: number; // Track total time spent on the property in seconds
15
  createdAt?: Date;
16
  updatedAt?: Date;
17
  }
 
25
  features: { type: Object },
26
  listing_url: { type: String },
27
  imgs: [],
28
+ views: { type: Number, default: 0 }, // New field to store the number of views
29
+ total_time_spent: { type: Number, default: 0 }, // New field to store total time spent in seconds
30
  createdAt: { type: Date, default: Date.now },
31
  updatedAt: { type: Date, default: Date.now },
32
  },