agrs-sequelize-sdk 1.1.57 → 1.1.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/models/AdPerformance.js +15 -0
- package/models/AdPerformanceHourly.js +15 -0
- package/models/Channel.js +27 -202
- package/models/RSOCFeedCampaign.js +80 -70
- package/package.json +1 -1
package/models/AdPerformance.js
CHANGED
|
@@ -35,6 +35,21 @@ module.exports = (sequelize, DataTypes) => {
|
|
|
35
35
|
type: DataTypes.INTEGER,
|
|
36
36
|
allowNull: true,
|
|
37
37
|
},
|
|
38
|
+
ViewContent: {
|
|
39
|
+
// New field
|
|
40
|
+
type: DataTypes.INTEGER,
|
|
41
|
+
allowNull: true,
|
|
42
|
+
},
|
|
43
|
+
Search: {
|
|
44
|
+
// New field
|
|
45
|
+
type: DataTypes.INTEGER,
|
|
46
|
+
allowNull: true,
|
|
47
|
+
},
|
|
48
|
+
Purchase: {
|
|
49
|
+
// New field
|
|
50
|
+
type: DataTypes.INTEGER,
|
|
51
|
+
allowNull: true,
|
|
52
|
+
},
|
|
38
53
|
originalSpend: {
|
|
39
54
|
type: DataTypes.FLOAT,
|
|
40
55
|
allowNull: true,
|
|
@@ -27,6 +27,21 @@ module.exports = (sequelize, DataTypes) => {
|
|
|
27
27
|
type: DataTypes.INTEGER,
|
|
28
28
|
allowNull: true,
|
|
29
29
|
},
|
|
30
|
+
ViewContent: {
|
|
31
|
+
// New field
|
|
32
|
+
type: DataTypes.INTEGER,
|
|
33
|
+
allowNull: true,
|
|
34
|
+
},
|
|
35
|
+
Search: {
|
|
36
|
+
// New field
|
|
37
|
+
type: DataTypes.INTEGER,
|
|
38
|
+
allowNull: true,
|
|
39
|
+
},
|
|
40
|
+
Purchase: {
|
|
41
|
+
// New field
|
|
42
|
+
type: DataTypes.INTEGER,
|
|
43
|
+
allowNull: true,
|
|
44
|
+
},
|
|
30
45
|
originalSpend: {
|
|
31
46
|
type: DataTypes.FLOAT,
|
|
32
47
|
allowNull: true,
|
package/models/Channel.js
CHANGED
|
@@ -1,230 +1,55 @@
|
|
|
1
1
|
module.exports = (sequelize, DataTypes) => {
|
|
2
|
-
const
|
|
3
|
-
"
|
|
2
|
+
const Channel = sequelize.define(
|
|
3
|
+
"Channel",
|
|
4
4
|
{
|
|
5
|
-
AGRS_CID: {
|
|
6
|
-
type: DataTypes.STRING,
|
|
7
|
-
allowNull: false,
|
|
8
|
-
unique: true,
|
|
9
|
-
primaryKey: true,
|
|
10
|
-
},
|
|
11
|
-
AGRSAID: {
|
|
12
|
-
type: DataTypes.STRING,
|
|
13
|
-
allowNull: false,
|
|
14
|
-
comment: "Foreign key referencing Article.AGRSAID",
|
|
15
|
-
},
|
|
16
|
-
articleName: {
|
|
17
|
-
type: DataTypes.STRING,
|
|
18
|
-
allowNull: false,
|
|
19
|
-
comment: "Name of the associated article",
|
|
20
|
-
},
|
|
21
5
|
channelId: {
|
|
22
6
|
type: DataTypes.STRING,
|
|
23
7
|
allowNull: false,
|
|
24
|
-
|
|
8
|
+
// Not setting as primary key or unique since duplicates are allowed
|
|
25
9
|
},
|
|
26
10
|
styleId: {
|
|
27
|
-
type: DataTypes.STRING,
|
|
28
|
-
allowNull: true,
|
|
29
|
-
comment: "Style ID (stid) inherited from Channel",
|
|
30
|
-
},
|
|
31
|
-
assignee: {
|
|
32
11
|
type: DataTypes.STRING,
|
|
33
12
|
allowNull: false,
|
|
34
13
|
},
|
|
35
14
|
status: {
|
|
36
15
|
type: DataTypes.STRING,
|
|
37
16
|
allowNull: false,
|
|
38
|
-
defaultValue: "
|
|
17
|
+
defaultValue: "free",
|
|
39
18
|
validate: {
|
|
40
|
-
isIn: [["
|
|
19
|
+
isIn: [["free", "used", "archived"]],
|
|
41
20
|
},
|
|
42
21
|
},
|
|
43
|
-
|
|
44
|
-
type: DataTypes.
|
|
45
|
-
allowNull: false,
|
|
46
|
-
},
|
|
47
|
-
vertical: {
|
|
48
|
-
type: DataTypes.STRING,
|
|
49
|
-
allowNull: false,
|
|
50
|
-
comment: "Maps to Article.category for dynamic selection",
|
|
51
|
-
},
|
|
52
|
-
freeText: {
|
|
53
|
-
type: DataTypes.TEXT,
|
|
54
|
-
allowNull: true,
|
|
55
|
-
},
|
|
56
|
-
campaignName: {
|
|
57
|
-
type: DataTypes.STRING,
|
|
58
|
-
allowNull: false,
|
|
59
|
-
},
|
|
60
|
-
campaignId: {
|
|
61
|
-
type: DataTypes.STRING,
|
|
62
|
-
allowNull: true,
|
|
63
|
-
},
|
|
64
|
-
keywords: {
|
|
65
|
-
type: DataTypes.ARRAY(DataTypes.STRING),
|
|
66
|
-
allowNull: true,
|
|
67
|
-
},
|
|
68
|
-
link: {
|
|
69
|
-
type: DataTypes.STRING(1024),
|
|
70
|
-
allowNull: true,
|
|
71
|
-
comment: "Campaign-specific URL based on article URL with parameters",
|
|
72
|
-
},
|
|
73
|
-
redirectLink: {
|
|
74
|
-
type: DataTypes.STRING(1024),
|
|
75
|
-
allowNull: true,
|
|
76
|
-
},
|
|
77
|
-
pixelId: {
|
|
78
|
-
type: DataTypes.STRING(1024),
|
|
79
|
-
allowNull: true,
|
|
80
|
-
},
|
|
81
|
-
token: {
|
|
82
|
-
type: DataTypes.STRING(1024),
|
|
83
|
-
allowNull: true,
|
|
84
|
-
},
|
|
85
|
-
accountId: {
|
|
86
|
-
type: DataTypes.STRING,
|
|
87
|
-
allowNull: false,
|
|
88
|
-
},
|
|
89
|
-
feedName: {
|
|
90
|
-
type: DataTypes.STRING,
|
|
91
|
-
allowNull: true,
|
|
92
|
-
defaultValue: "RSOC",
|
|
93
|
-
},
|
|
94
|
-
adTitle: {
|
|
95
|
-
type: DataTypes.STRING,
|
|
96
|
-
allowNull: true,
|
|
97
|
-
},
|
|
98
|
-
domain: {
|
|
99
|
-
type: DataTypes.STRING,
|
|
100
|
-
allowNull: true,
|
|
101
|
-
},
|
|
102
|
-
feedProvider: {
|
|
103
|
-
type: DataTypes.STRING,
|
|
104
|
-
allowNull: false,
|
|
105
|
-
defaultValue: "RSOC",
|
|
106
|
-
},
|
|
107
|
-
createdCampaignAt: {
|
|
108
|
-
type: DataTypes.DATE,
|
|
109
|
-
allowNull: true,
|
|
110
|
-
defaultValue: DataTypes.NOW,
|
|
111
|
-
},
|
|
112
|
-
draft: {
|
|
113
|
-
type: DataTypes.BOOLEAN,
|
|
114
|
-
allowNull: true,
|
|
115
|
-
defaultValue: false,
|
|
116
|
-
},
|
|
117
|
-
createdAt: {
|
|
118
|
-
type: DataTypes.DATE,
|
|
119
|
-
defaultValue: DataTypes.NOW,
|
|
120
|
-
},
|
|
121
|
-
updatedAt: {
|
|
122
|
-
type: DataTypes.DATE,
|
|
123
|
-
defaultValue: DataTypes.NOW,
|
|
124
|
-
},
|
|
125
|
-
platform: {
|
|
126
|
-
type: DataTypes.STRING,
|
|
22
|
+
connectedCampaigns: {
|
|
23
|
+
type: DataTypes.JSONB, // Use JSONB for better querying capabilities
|
|
127
24
|
allowNull: false,
|
|
128
|
-
|
|
129
|
-
mediaBuyer: {
|
|
130
|
-
type: DataTypes.STRING,
|
|
131
|
-
allowNull: true,
|
|
25
|
+
defaultValue: [],
|
|
132
26
|
},
|
|
133
27
|
},
|
|
134
28
|
{
|
|
135
|
-
tableName: "
|
|
29
|
+
tableName: "channels",
|
|
136
30
|
timestamps: true,
|
|
31
|
+
indexes: [
|
|
32
|
+
// Add a composite unique index on channelId and styleId if needed
|
|
33
|
+
{
|
|
34
|
+
unique: true,
|
|
35
|
+
fields: ["channelId", "styleId"],
|
|
36
|
+
name: "unique_channel_style",
|
|
37
|
+
},
|
|
38
|
+
],
|
|
137
39
|
}
|
|
138
40
|
);
|
|
139
41
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
RSOCFeedCampaign.belongsTo(models.Channel, {
|
|
149
|
-
foreignKey: "channelId",
|
|
150
|
-
targetKey: "channelId",
|
|
151
|
-
as: "Channel",
|
|
152
|
-
constraints: false, // Disable foreign key constraint
|
|
153
|
-
});
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
RSOCFeedCampaign.beforeCreate(async (campaign) => {
|
|
157
|
-
// Set redirectLink to null as requested
|
|
158
|
-
campaign.setDataValue("redirectLink", null);
|
|
159
|
-
|
|
160
|
-
const channel = await sequelize.models.Channel.findOne({
|
|
161
|
-
where: { channelId: campaign.channelId, styleId: campaign.styleId },
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
if (channel) {
|
|
165
|
-
const connectedCampaigns = channel.connectedCampaigns || [];
|
|
166
|
-
if (!connectedCampaigns.some((c) => c.campaignId === campaign.AGRS_CID)) {
|
|
167
|
-
connectedCampaigns.push({
|
|
168
|
-
campaignId: campaign.AGRS_CID,
|
|
169
|
-
assignedAt: new Date(),
|
|
170
|
-
releasedAt: null,
|
|
171
|
-
});
|
|
172
|
-
await channel.update({ status: "used", connectedCampaigns });
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
RSOCFeedCampaign.beforeUpdate(async (campaign) => {
|
|
178
|
-
// Ensure redirectLink remains null
|
|
179
|
-
campaign.setDataValue("redirectLink", null);
|
|
180
|
-
|
|
181
|
-
if (campaign.changed("channelId") || campaign.changed("styleId")) {
|
|
182
|
-
const oldChannelId = campaign.previous("channelId");
|
|
183
|
-
const oldStyleId = campaign.previous("styleId");
|
|
184
|
-
const newChannelId = campaign.channelId;
|
|
185
|
-
const newStyleId = campaign.styleId;
|
|
186
|
-
|
|
187
|
-
if (oldChannelId) {
|
|
188
|
-
const oldChannel = await sequelize.models.Channel.findOne({
|
|
189
|
-
where: { channelId: oldChannelId, styleId: oldStyleId },
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
if (oldChannel) {
|
|
193
|
-
const connectedCampaigns = oldChannel.connectedCampaigns || [];
|
|
194
|
-
const updatedCampaigns = connectedCampaigns
|
|
195
|
-
.map((c) =>
|
|
196
|
-
c.campaignId === campaign.AGRS_CID
|
|
197
|
-
? { ...c, releasedAt: new Date() }
|
|
198
|
-
: c
|
|
199
|
-
)
|
|
200
|
-
.filter((c) => c.releasedAt === null);
|
|
201
|
-
|
|
202
|
-
await oldChannel.update({
|
|
203
|
-
connectedCampaigns: updatedCampaigns,
|
|
204
|
-
status: updatedCampaigns.length > 0 ? "used" : "free",
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
const newChannel = await sequelize.models.Channel.findOne({
|
|
210
|
-
where: { channelId: newChannelId, styleId: newStyleId },
|
|
42
|
+
// Define associations without enforcing constraints
|
|
43
|
+
Channel.associate = (models) => {
|
|
44
|
+
if (models.RSOCFeedCampaign) {
|
|
45
|
+
Channel.hasMany(models.RSOCFeedCampaign, {
|
|
46
|
+
foreignKey: "channelId",
|
|
47
|
+
sourceKey: "channelId",
|
|
48
|
+
as: "RSOCFeedCampaigns",
|
|
49
|
+
constraints: false, // Disable FK constraint
|
|
211
50
|
});
|
|
212
|
-
|
|
213
|
-
if (newChannel) {
|
|
214
|
-
const connectedCampaigns = newChannel.connectedCampaigns || [];
|
|
215
|
-
if (
|
|
216
|
-
!connectedCampaigns.some((c) => c.campaignId === campaign.AGRS_CID)
|
|
217
|
-
) {
|
|
218
|
-
connectedCampaigns.push({
|
|
219
|
-
campaignId: campaign.AGRS_CID,
|
|
220
|
-
assignedAt: new Date(),
|
|
221
|
-
releasedAt: null,
|
|
222
|
-
});
|
|
223
|
-
await newChannel.update({ status: "used", connectedCampaigns });
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
51
|
}
|
|
227
|
-
}
|
|
52
|
+
};
|
|
228
53
|
|
|
229
|
-
return
|
|
54
|
+
return Channel;
|
|
230
55
|
};
|
|
@@ -135,7 +135,7 @@ module.exports = (sequelize, DataTypes) => {
|
|
|
135
135
|
},
|
|
136
136
|
{
|
|
137
137
|
tableName: "rsoc_feed_campaigns",
|
|
138
|
-
timestamps: true,
|
|
138
|
+
timestamps: true,
|
|
139
139
|
}
|
|
140
140
|
);
|
|
141
141
|
|
|
@@ -146,7 +146,7 @@ module.exports = (sequelize, DataTypes) => {
|
|
|
146
146
|
foreignKey: "AGRSAID",
|
|
147
147
|
targetKey: "AGRSAID",
|
|
148
148
|
as: "Article",
|
|
149
|
-
constraints: false,
|
|
149
|
+
constraints: false,
|
|
150
150
|
});
|
|
151
151
|
}
|
|
152
152
|
|
|
@@ -155,20 +155,23 @@ module.exports = (sequelize, DataTypes) => {
|
|
|
155
155
|
foreignKey: "channelId",
|
|
156
156
|
targetKey: "channelId",
|
|
157
157
|
as: "Channel",
|
|
158
|
-
constraints: false,
|
|
158
|
+
constraints: false,
|
|
159
159
|
});
|
|
160
160
|
}
|
|
161
161
|
};
|
|
162
162
|
|
|
163
163
|
// BeforeCreate hook: Update Channel status and connectedCampaigns
|
|
164
164
|
RSOCFeedCampaign.beforeCreate(async (campaign, options) => {
|
|
165
|
-
campaign.setDataValue("redirectLink", null);
|
|
165
|
+
campaign.setDataValue("redirectLink", null);
|
|
166
|
+
|
|
167
|
+
// Skip channel update if in a silent operation (e.g., during sync)
|
|
168
|
+
if (options.silent) return;
|
|
166
169
|
|
|
167
170
|
try {
|
|
168
171
|
const channel = await sequelize.models.Channel.findOne({
|
|
169
172
|
where: {
|
|
170
173
|
channelId: campaign.channelId,
|
|
171
|
-
styleId: campaign.styleId || null,
|
|
174
|
+
styleId: campaign.styleId || null,
|
|
172
175
|
},
|
|
173
176
|
});
|
|
174
177
|
|
|
@@ -187,7 +190,7 @@ module.exports = (sequelize, DataTypes) => {
|
|
|
187
190
|
status: "used",
|
|
188
191
|
connectedCampaigns,
|
|
189
192
|
},
|
|
190
|
-
{ silent: true }
|
|
193
|
+
{ silent: true }
|
|
191
194
|
);
|
|
192
195
|
}
|
|
193
196
|
} else {
|
|
@@ -197,85 +200,92 @@ module.exports = (sequelize, DataTypes) => {
|
|
|
197
200
|
}
|
|
198
201
|
} catch (error) {
|
|
199
202
|
console.error("Error in beforeCreate hook:", error.message);
|
|
200
|
-
// Log error but don't throw to allow campaign creation to proceed
|
|
201
203
|
}
|
|
202
204
|
});
|
|
203
205
|
|
|
204
206
|
// BeforeUpdate hook: Handle channel reassignment
|
|
205
207
|
RSOCFeedCampaign.beforeUpdate(async (campaign, options) => {
|
|
206
|
-
campaign.setDataValue("redirectLink", null);
|
|
207
|
-
|
|
208
|
-
if (campaign.changed("channelId") || campaign.changed("styleId")) {
|
|
209
|
-
try {
|
|
210
|
-
const oldChannelId = campaign.previous("channelId");
|
|
211
|
-
const oldStyleId = campaign.previous("styleId") || null;
|
|
212
|
-
const newChannelId = campaign.channelId;
|
|
213
|
-
const newStyleId = campaign.styleId || null;
|
|
214
|
-
|
|
215
|
-
// Release old channel
|
|
216
|
-
if (oldChannelId) {
|
|
217
|
-
const oldChannel = await sequelize.models.Channel.findOne({
|
|
218
|
-
where: {
|
|
219
|
-
channelId: oldChannelId,
|
|
220
|
-
styleId: oldStyleId,
|
|
221
|
-
},
|
|
222
|
-
});
|
|
208
|
+
campaign.setDataValue("redirectLink", null);
|
|
223
209
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
)
|
|
232
|
-
.filter((c) => !c.releasedAt); // Remove released campaigns
|
|
210
|
+
// Skip channel update if in a silent operation or no relevant changes
|
|
211
|
+
if (
|
|
212
|
+
options.silent ||
|
|
213
|
+
(!campaign.changed("channelId") && !campaign.changed("styleId"))
|
|
214
|
+
) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
233
217
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
{ silent: true }
|
|
240
|
-
);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
218
|
+
try {
|
|
219
|
+
const oldChannelId = campaign.previous("channelId");
|
|
220
|
+
const oldStyleId = campaign.previous("styleId") || null;
|
|
221
|
+
const newChannelId = campaign.channelId;
|
|
222
|
+
const newStyleId = campaign.styleId || null;
|
|
243
223
|
|
|
244
|
-
|
|
245
|
-
|
|
224
|
+
// Release old channel
|
|
225
|
+
if (
|
|
226
|
+
oldChannelId &&
|
|
227
|
+
(oldChannelId !== newChannelId || oldStyleId !== newStyleId)
|
|
228
|
+
) {
|
|
229
|
+
const oldChannel = await sequelize.models.Channel.findOne({
|
|
246
230
|
where: {
|
|
247
|
-
channelId:
|
|
248
|
-
styleId:
|
|
231
|
+
channelId: oldChannelId,
|
|
232
|
+
styleId: oldStyleId,
|
|
249
233
|
},
|
|
250
234
|
});
|
|
251
235
|
|
|
252
|
-
if (
|
|
253
|
-
const connectedCampaigns =
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
} else {
|
|
271
|
-
console.warn(
|
|
272
|
-
`New channel not found for channelId: ${newChannelId}, styleId: ${newStyleId}`
|
|
236
|
+
if (oldChannel) {
|
|
237
|
+
const connectedCampaigns = oldChannel.connectedCampaigns || [];
|
|
238
|
+
const updatedCampaigns = connectedCampaigns
|
|
239
|
+
.map((c) =>
|
|
240
|
+
c.campaignId === campaign.AGRS_CID
|
|
241
|
+
? { ...c, releasedAt: new Date() }
|
|
242
|
+
: c
|
|
243
|
+
)
|
|
244
|
+
.filter((c) => !c.releasedAt);
|
|
245
|
+
|
|
246
|
+
await oldChannel.update(
|
|
247
|
+
{
|
|
248
|
+
connectedCampaigns: updatedCampaigns,
|
|
249
|
+
status: updatedCampaigns.length > 0 ? "used" : "free",
|
|
250
|
+
},
|
|
251
|
+
{ silent: true }
|
|
273
252
|
);
|
|
274
253
|
}
|
|
275
|
-
} catch (error) {
|
|
276
|
-
console.error("Error in beforeUpdate hook:", error.message);
|
|
277
|
-
// Log error but don't throw to allow update to proceed
|
|
278
254
|
}
|
|
255
|
+
|
|
256
|
+
// Assign new channel
|
|
257
|
+
const newChannel = await sequelize.models.Channel.findOne({
|
|
258
|
+
where: {
|
|
259
|
+
channelId: newChannelId,
|
|
260
|
+
styleId: newStyleId,
|
|
261
|
+
},
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
if (newChannel) {
|
|
265
|
+
const connectedCampaigns = newChannel.connectedCampaigns || [];
|
|
266
|
+
if (
|
|
267
|
+
!connectedCampaigns.some((c) => c.campaignId === campaign.AGRS_CID)
|
|
268
|
+
) {
|
|
269
|
+
connectedCampaigns.push({
|
|
270
|
+
campaignId: campaign.AGRS_CID,
|
|
271
|
+
assignedAt: new Date(),
|
|
272
|
+
releasedAt: null,
|
|
273
|
+
});
|
|
274
|
+
await newChannel.update(
|
|
275
|
+
{
|
|
276
|
+
status: "used",
|
|
277
|
+
connectedCampaigns,
|
|
278
|
+
},
|
|
279
|
+
{ silent: true }
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
} else {
|
|
283
|
+
console.warn(
|
|
284
|
+
`New channel not found for channelId: ${newChannelId}, styleId: ${newStyleId}`
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
} catch (error) {
|
|
288
|
+
console.error("Error in beforeUpdate hook:", error.message);
|
|
279
289
|
}
|
|
280
290
|
});
|
|
281
291
|
|