agrs-sequelize-sdk 1.1.56 → 1.1.58
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/Channel.js +27 -202
- package/models/RSOCFeedCampaign.js +108 -108
- package/package.json +1 -1
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
|
};
|
|
@@ -116,10 +116,12 @@ module.exports = (sequelize, DataTypes) => {
|
|
|
116
116
|
},
|
|
117
117
|
createdAt: {
|
|
118
118
|
type: DataTypes.DATE,
|
|
119
|
+
allowNull: false,
|
|
119
120
|
defaultValue: DataTypes.NOW,
|
|
120
121
|
},
|
|
121
122
|
updatedAt: {
|
|
122
123
|
type: DataTypes.DATE,
|
|
124
|
+
allowNull: false,
|
|
123
125
|
defaultValue: DataTypes.NOW,
|
|
124
126
|
},
|
|
125
127
|
platform: {
|
|
@@ -134,158 +136,156 @@ module.exports = (sequelize, DataTypes) => {
|
|
|
134
136
|
{
|
|
135
137
|
tableName: "rsoc_feed_campaigns",
|
|
136
138
|
timestamps: true,
|
|
137
|
-
// Entirely disable automatic foreign key creation
|
|
138
|
-
references: false,
|
|
139
139
|
}
|
|
140
140
|
);
|
|
141
141
|
|
|
142
|
-
//
|
|
143
|
-
RSOCFeedCampaign.associate =
|
|
144
|
-
// Define associations without foreign key constraints
|
|
145
|
-
const queryOptions = { constraints: false };
|
|
146
|
-
|
|
147
|
-
// Associate with Article model
|
|
142
|
+
// Define associations without enforcing foreign key constraints
|
|
143
|
+
RSOCFeedCampaign.associate = (models) => {
|
|
148
144
|
if (models.Article) {
|
|
149
145
|
RSOCFeedCampaign.belongsTo(models.Article, {
|
|
150
146
|
foreignKey: "AGRSAID",
|
|
151
147
|
targetKey: "AGRSAID",
|
|
152
148
|
as: "Article",
|
|
153
|
-
|
|
149
|
+
constraints: false,
|
|
154
150
|
});
|
|
155
151
|
}
|
|
156
152
|
|
|
157
|
-
// Associate with Channel model
|
|
158
153
|
if (models.Channel) {
|
|
159
154
|
RSOCFeedCampaign.belongsTo(models.Channel, {
|
|
160
155
|
foreignKey: "channelId",
|
|
161
156
|
targetKey: "channelId",
|
|
162
157
|
as: "Channel",
|
|
163
|
-
|
|
158
|
+
constraints: false,
|
|
164
159
|
});
|
|
165
160
|
}
|
|
166
161
|
};
|
|
167
162
|
|
|
163
|
+
// BeforeCreate hook: Update Channel status and connectedCampaigns
|
|
168
164
|
RSOCFeedCampaign.beforeCreate(async (campaign, options) => {
|
|
169
|
-
// Set redirectLink to null as requested
|
|
170
165
|
campaign.setDataValue("redirectLink", null);
|
|
171
166
|
|
|
172
|
-
//
|
|
173
|
-
if (
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
167
|
+
// Skip channel update if in a silent operation (e.g., during sync)
|
|
168
|
+
if (options.silent) return;
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
const channel = await sequelize.models.Channel.findOne({
|
|
172
|
+
where: {
|
|
173
|
+
channelId: campaign.channelId,
|
|
174
|
+
styleId: campaign.styleId || null,
|
|
175
|
+
},
|
|
176
|
+
});
|
|
181
177
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
178
|
+
if (channel) {
|
|
179
|
+
const connectedCampaigns = channel.connectedCampaigns || [];
|
|
180
|
+
if (
|
|
181
|
+
!connectedCampaigns.some((c) => c.campaignId === campaign.AGRS_CID)
|
|
182
|
+
) {
|
|
183
|
+
connectedCampaigns.push({
|
|
184
|
+
campaignId: campaign.AGRS_CID,
|
|
185
|
+
assignedAt: new Date(),
|
|
186
|
+
releasedAt: null,
|
|
187
|
+
});
|
|
188
|
+
await channel.update(
|
|
189
|
+
{
|
|
190
|
+
status: "used",
|
|
191
|
+
connectedCampaigns,
|
|
192
|
+
},
|
|
193
|
+
{ silent: true }
|
|
194
|
+
);
|
|
200
195
|
}
|
|
201
|
-
}
|
|
202
|
-
console.
|
|
203
|
-
|
|
204
|
-
error.message
|
|
196
|
+
} else {
|
|
197
|
+
console.warn(
|
|
198
|
+
`Channel not found for channelId: ${campaign.channelId}, styleId: ${campaign.styleId}`
|
|
205
199
|
);
|
|
206
|
-
// Continue with campaign creation even if channel update fails
|
|
207
200
|
}
|
|
201
|
+
} catch (error) {
|
|
202
|
+
console.error("Error in beforeCreate hook:", error.message);
|
|
208
203
|
}
|
|
209
204
|
});
|
|
210
205
|
|
|
206
|
+
// BeforeUpdate hook: Handle channel reassignment
|
|
211
207
|
RSOCFeedCampaign.beforeUpdate(async (campaign, options) => {
|
|
212
|
-
// Ensure redirectLink remains null
|
|
213
208
|
campaign.setDataValue("redirectLink", null);
|
|
214
209
|
|
|
215
|
-
//
|
|
210
|
+
// Skip channel update if in a silent operation or no relevant changes
|
|
216
211
|
if (
|
|
217
|
-
|
|
218
|
-
(campaign.changed("channelId")
|
|
212
|
+
options.silent ||
|
|
213
|
+
(!campaign.changed("channelId") && !campaign.changed("styleId"))
|
|
219
214
|
) {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const oldStyleId = campaign.previous("styleId");
|
|
223
|
-
const newChannelId = campaign.channelId;
|
|
224
|
-
const newStyleId = campaign.styleId;
|
|
225
|
-
|
|
226
|
-
// Update old channel if exists
|
|
227
|
-
if (oldChannelId) {
|
|
228
|
-
const oldChannel = await sequelize.models.Channel.findOne({
|
|
229
|
-
where: {
|
|
230
|
-
channelId: oldChannelId,
|
|
231
|
-
styleId: oldStyleId,
|
|
232
|
-
},
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
if (oldChannel) {
|
|
236
|
-
const connectedCampaigns = oldChannel.connectedCampaigns || [];
|
|
237
|
-
const updatedCampaigns = connectedCampaigns
|
|
238
|
-
.map((c) =>
|
|
239
|
-
c.campaignId === campaign.AGRS_CID
|
|
240
|
-
? { ...c, releasedAt: new Date() }
|
|
241
|
-
: c
|
|
242
|
-
)
|
|
243
|
-
.filter((c) => c.releasedAt === null);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
244
217
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
{ silent: true }
|
|
251
|
-
);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
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;
|
|
254
223
|
|
|
255
|
-
|
|
256
|
-
|
|
224
|
+
// Release old channel
|
|
225
|
+
if (
|
|
226
|
+
oldChannelId &&
|
|
227
|
+
(oldChannelId !== newChannelId || oldStyleId !== newStyleId)
|
|
228
|
+
) {
|
|
229
|
+
const oldChannel = await sequelize.models.Channel.findOne({
|
|
257
230
|
where: {
|
|
258
|
-
channelId:
|
|
259
|
-
styleId:
|
|
231
|
+
channelId: oldChannelId,
|
|
232
|
+
styleId: oldStyleId,
|
|
260
233
|
},
|
|
261
234
|
});
|
|
262
235
|
|
|
263
|
-
if (
|
|
264
|
-
const connectedCampaigns =
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
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 }
|
|
252
|
+
);
|
|
253
|
+
}
|
|
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
281
|
}
|
|
282
|
-
}
|
|
283
|
-
console.
|
|
284
|
-
|
|
285
|
-
error.message
|
|
282
|
+
} else {
|
|
283
|
+
console.warn(
|
|
284
|
+
`New channel not found for channelId: ${newChannelId}, styleId: ${newStyleId}`
|
|
286
285
|
);
|
|
287
|
-
// Continue with campaign update even if channel updates fail
|
|
288
286
|
}
|
|
287
|
+
} catch (error) {
|
|
288
|
+
console.error("Error in beforeUpdate hook:", error.message);
|
|
289
289
|
}
|
|
290
290
|
});
|
|
291
291
|
|