nodebb-plugin-sso-biogrenci 1.0.1 → 1.0.2
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/.claude/settings.local.json +2 -1
- package/library.js +129 -28
- package/package.json +1 -1
- package/static/lib/admin.js +24 -9
- package/static/lib/biogrenci-firsatlar.js +55 -17
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
"allow": [
|
|
4
4
|
"Bash(tree -L 3 -I 'node_modules' /c/Users/kadir/OneDrive/Masaüstü/Projeler/nodebb-plugin-sso-biogrenci/ 2>/dev/null || find /c/Users/kadir/OneDrive/Masaüstü/Projeler/nodebb-plugin-sso-biogrenci -not -path '*/node_modules/*' -type f | sort)",
|
|
5
5
|
"WebFetch(domain:raw.githubusercontent.com)",
|
|
6
|
-
"Bash(xargs grep:*)"
|
|
6
|
+
"Bash(xargs grep:*)",
|
|
7
|
+
"WebFetch(domain:biogrenci.com)"
|
|
7
8
|
]
|
|
8
9
|
}
|
|
9
10
|
}
|
package/library.js
CHANGED
|
@@ -7,8 +7,11 @@ const user = require.main.require('./src/user');
|
|
|
7
7
|
const db = require.main.require('./src/database');
|
|
8
8
|
const meta = require.main.require('./src/meta');
|
|
9
9
|
const groups = require.main.require('./src/groups');
|
|
10
|
+
const winston = require.main.require('winston');
|
|
10
11
|
const authenticationController = require.main.require('./src/controllers/authentication');
|
|
11
12
|
|
|
13
|
+
const LOG_PREFIX = '[sso-biogrenci]';
|
|
14
|
+
|
|
12
15
|
const constants = {
|
|
13
16
|
name: 'biogrenci',
|
|
14
17
|
displayName: "bi'öğrenci",
|
|
@@ -25,70 +28,91 @@ const plugin = {
|
|
|
25
28
|
clientId: '019ccf3d-0032-70e0-bf69-474e3f4dd2fa',
|
|
26
29
|
clientSecret: '0bpVolqxVtNGcrZuVWtWjNfKr36EABj8zzj61e6i',
|
|
27
30
|
},
|
|
31
|
+
ready: false,
|
|
28
32
|
};
|
|
29
33
|
|
|
30
34
|
plugin.init = async function (params) {
|
|
31
35
|
const { router, middleware } = params;
|
|
36
|
+
winston.info(`${LOG_PREFIX} Initializing plugin...`);
|
|
32
37
|
|
|
33
38
|
// Admin settings page
|
|
34
39
|
router.get('/admin/plugins/sso-biogrenci', middleware.admin.buildHeader, renderAdmin);
|
|
35
40
|
router.get('/api/admin/plugins/sso-biogrenci', renderAdmin);
|
|
41
|
+
winston.info(`${LOG_PREFIX} Admin routes registered`);
|
|
36
42
|
|
|
37
43
|
// Firsatlar (discounts) page
|
|
38
44
|
router.get('/firsatlar', middleware.buildHeader, renderFirsatlar);
|
|
39
45
|
router.get('/api/firsatlar', renderFirsatlar);
|
|
46
|
+
winston.info(`${LOG_PREFIX} Firsatlar routes registered`);
|
|
40
47
|
|
|
41
48
|
// API: fetch opportunities from bi'ogrenci
|
|
42
49
|
router.get('/api/biogrenci/firsatlar', async (req, res) => {
|
|
50
|
+
winston.info(`${LOG_PREFIX} GET /api/biogrenci/firsatlar query=%j`, req.query);
|
|
43
51
|
try {
|
|
44
52
|
const data = await fetchOpportunities(req.query);
|
|
53
|
+
winston.info(`${LOG_PREFIX} Firsatlar response: %d items`, data.data ? data.data.length : 0);
|
|
45
54
|
res.json(data);
|
|
46
55
|
} catch (err) {
|
|
56
|
+
winston.error(`${LOG_PREFIX} Firsatlar fetch error: %s`, err.message);
|
|
47
57
|
res.status(500).json({ error: err.message });
|
|
48
58
|
}
|
|
49
59
|
});
|
|
50
60
|
|
|
51
61
|
// API: claim an opportunity
|
|
52
62
|
router.post('/api/biogrenci/firsatlar/:id/claim', async (req, res) => {
|
|
63
|
+
winston.info(`${LOG_PREFIX} POST claim opportunity id=%s uid=%s`, req.params.id, req.uid);
|
|
53
64
|
if (!req.uid) {
|
|
54
65
|
return res.status(401).json({ error: 'Giriş yapmanız gerekiyor' });
|
|
55
66
|
}
|
|
56
67
|
try {
|
|
57
68
|
const accessToken = await db.getObjectField(`biogrenci:uid:${req.uid}`, 'accessToken');
|
|
58
69
|
if (!accessToken) {
|
|
70
|
+
winston.warn(`${LOG_PREFIX} No access token for uid=%s`, req.uid);
|
|
59
71
|
return res.status(403).json({ error: "bi'öğrenci hesabınızla giriş yapmalısınız" });
|
|
60
72
|
}
|
|
61
|
-
const
|
|
73
|
+
const url = `${constants.partnerAPIBase}/opportunities/${req.params.id}/claim`;
|
|
74
|
+
winston.info(`${LOG_PREFIX} Claiming: POST %s`, url);
|
|
75
|
+
const response = await fetch(url, {
|
|
62
76
|
method: 'POST',
|
|
63
77
|
headers: { Authorization: `Bearer ${accessToken}` },
|
|
64
78
|
});
|
|
65
79
|
const data = await response.json();
|
|
80
|
+
winston.info(`${LOG_PREFIX} Claim response status=%d data=%j`, response.status, data);
|
|
66
81
|
res.json(data);
|
|
67
82
|
} catch (err) {
|
|
83
|
+
winston.error(`${LOG_PREFIX} Claim error: %s`, err.message);
|
|
68
84
|
res.status(500).json({ error: err.message });
|
|
69
85
|
}
|
|
70
86
|
});
|
|
71
87
|
|
|
72
88
|
// Profile: link/unlink bi'öğrenci account
|
|
73
89
|
router.get('/api/biogrenci/status', async (req, res) => {
|
|
90
|
+
winston.verbose(`${LOG_PREFIX} GET /api/biogrenci/status uid=%s`, req.uid);
|
|
74
91
|
if (!req.uid) {
|
|
75
92
|
return res.json({ linked: false });
|
|
76
93
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
94
|
+
try {
|
|
95
|
+
const data = await db.getObject(`biogrenci:uid:${req.uid}`);
|
|
96
|
+
if (data && data.biogrenciId) {
|
|
97
|
+
const education = await user.getUserField(req.uid, 'biogrenci_education');
|
|
98
|
+
const verified = await user.getUserField(req.uid, 'biogrenci_verified');
|
|
99
|
+
winston.verbose(`${LOG_PREFIX} Status: linked=true verified=%s`, !!verified);
|
|
100
|
+
return res.json({
|
|
101
|
+
linked: true,
|
|
102
|
+
biogrenciId: data.biogrenciId,
|
|
103
|
+
education: education || null,
|
|
104
|
+
verified: !!verified,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
res.json({ linked: false });
|
|
108
|
+
} catch (err) {
|
|
109
|
+
winston.error(`${LOG_PREFIX} Status error: %s`, err.message);
|
|
110
|
+
res.json({ linked: false });
|
|
87
111
|
}
|
|
88
|
-
res.json({ linked: false });
|
|
89
112
|
});
|
|
90
113
|
|
|
91
114
|
router.post('/api/biogrenci/unlink', async (req, res) => {
|
|
115
|
+
winston.info(`${LOG_PREFIX} POST /api/biogrenci/unlink uid=%s`, req.uid);
|
|
92
116
|
if (!req.uid) {
|
|
93
117
|
return res.status(401).json({ error: 'Giriş yapmanız gerekiyor' });
|
|
94
118
|
}
|
|
@@ -102,20 +126,36 @@ plugin.init = async function (params) {
|
|
|
102
126
|
await user.setUserField(req.uid, 'biogrenci_education', '');
|
|
103
127
|
await user.setUserField(req.uid, 'biogrenci_verified', false);
|
|
104
128
|
await groups.leave('Doğrulanmış Öğrenciler', req.uid);
|
|
129
|
+
winston.info(`${LOG_PREFIX} Unlinked uid=%s`, req.uid);
|
|
105
130
|
res.json({ success: true });
|
|
106
131
|
} catch (err) {
|
|
132
|
+
winston.error(`${LOG_PREFIX} Unlink error: %s`, err.message);
|
|
107
133
|
res.status(500).json({ error: err.message });
|
|
108
134
|
}
|
|
109
135
|
});
|
|
110
136
|
|
|
111
137
|
// Load settings from DB
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
138
|
+
try {
|
|
139
|
+
const settings = await meta.settings.get('sso-biogrenci');
|
|
140
|
+
winston.info(`${LOG_PREFIX} Loaded settings from DB: clientId=%s clientSecret=%s`,
|
|
141
|
+
settings.clientId ? settings.clientId.substring(0, 8) + '...' : '(empty)',
|
|
142
|
+
settings.clientSecret ? '***set***' : '(empty)'
|
|
143
|
+
);
|
|
144
|
+
if (settings.clientId) plugin.settings.clientId = settings.clientId;
|
|
145
|
+
if (settings.clientSecret) plugin.settings.clientSecret = settings.clientSecret;
|
|
146
|
+
} catch (err) {
|
|
147
|
+
winston.error(`${LOG_PREFIX} Failed to load settings: %s`, err.message);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
plugin.ready = true;
|
|
151
|
+
winston.info(`${LOG_PREFIX} Plugin initialized. clientId=%s`,
|
|
152
|
+
plugin.settings.clientId ? plugin.settings.clientId.substring(0, 8) + '...' : '(not set)'
|
|
153
|
+
);
|
|
115
154
|
};
|
|
116
155
|
|
|
117
156
|
async function renderAdmin(req, res) {
|
|
118
157
|
const callbackURL = nconf.get('url') + '/auth/biogrenci/callback';
|
|
158
|
+
winston.verbose(`${LOG_PREFIX} Rendering admin page, callbackURL=%s`, callbackURL);
|
|
119
159
|
res.render('admin/plugins/sso-biogrenci', {
|
|
120
160
|
title: "bi'öğrenci SSO",
|
|
121
161
|
callbackURL: callbackURL,
|
|
@@ -123,6 +163,7 @@ async function renderAdmin(req, res) {
|
|
|
123
163
|
}
|
|
124
164
|
|
|
125
165
|
async function renderFirsatlar(req, res) {
|
|
166
|
+
winston.verbose(`${LOG_PREFIX} Rendering firsatlar page, uid=%s`, req.uid);
|
|
126
167
|
res.render('biogrenci-firsatlar', {
|
|
127
168
|
title: 'Öğrenci Fırsatları',
|
|
128
169
|
uid: req.uid || 0,
|
|
@@ -139,19 +180,42 @@ async function fetchOpportunities(query) {
|
|
|
139
180
|
params.set('page', query.page || 1);
|
|
140
181
|
params.set('per_page', query.per_page || 20);
|
|
141
182
|
|
|
142
|
-
const
|
|
183
|
+
const url = `${constants.partnerAPIBase}/opportunities?${params.toString()}`;
|
|
184
|
+
winston.info(`${LOG_PREFIX} Fetching opportunities: GET %s`, url);
|
|
185
|
+
|
|
186
|
+
const response = await fetch(url, {
|
|
187
|
+
headers: {
|
|
188
|
+
'Accept': 'application/json',
|
|
189
|
+
'X-Client-Id': plugin.settings.clientId,
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
winston.info(`${LOG_PREFIX} Partner API response: status=%d`, response.status);
|
|
194
|
+
|
|
143
195
|
if (!response.ok) {
|
|
196
|
+
const body = await response.text();
|
|
197
|
+
winston.error(`${LOG_PREFIX} Partner API error: status=%d body=%s`, response.status, body);
|
|
144
198
|
throw new Error(`Partner API error: ${response.status}`);
|
|
145
199
|
}
|
|
146
|
-
|
|
200
|
+
|
|
201
|
+
const data = await response.json();
|
|
202
|
+
winston.info(`${LOG_PREFIX} Partner API data keys=%j`, Object.keys(data));
|
|
203
|
+
return data;
|
|
147
204
|
}
|
|
148
205
|
|
|
149
206
|
plugin.getStrategy = async function (strategies) {
|
|
207
|
+
winston.info(`${LOG_PREFIX} getStrategy called. clientId=%s clientSecret=%s`,
|
|
208
|
+
plugin.settings.clientId ? 'set' : 'NOT SET',
|
|
209
|
+
plugin.settings.clientSecret ? 'set' : 'NOT SET'
|
|
210
|
+
);
|
|
211
|
+
|
|
150
212
|
if (!plugin.settings.clientId || !plugin.settings.clientSecret) {
|
|
213
|
+
winston.warn(`${LOG_PREFIX} Missing credentials, skipping strategy registration`);
|
|
151
214
|
return strategies;
|
|
152
215
|
}
|
|
153
216
|
|
|
154
217
|
const callbackURL = nconf.get('url') + '/auth/biogrenci/callback';
|
|
218
|
+
winston.info(`${LOG_PREFIX} Registering OAuth2 strategy, callbackURL=%s`, callbackURL);
|
|
155
219
|
|
|
156
220
|
const strategy = new OAuth2Strategy(
|
|
157
221
|
{
|
|
@@ -164,19 +228,36 @@ plugin.getStrategy = async function (strategies) {
|
|
|
164
228
|
passReqToCallback: true,
|
|
165
229
|
},
|
|
166
230
|
async (req, accessToken, refreshToken, params, profile, done) => {
|
|
231
|
+
winston.info(`${LOG_PREFIX} OAuth2 callback received. accessToken=%s refreshToken=%s`,
|
|
232
|
+
accessToken ? accessToken.substring(0, 10) + '...' : 'none',
|
|
233
|
+
refreshToken ? 'set' : 'none'
|
|
234
|
+
);
|
|
167
235
|
try {
|
|
168
236
|
// Fetch user info from bi'ogrenci
|
|
237
|
+
winston.info(`${LOG_PREFIX} Fetching userinfo from %s`, constants.userInfoURL);
|
|
169
238
|
const response = await fetch(constants.userInfoURL, {
|
|
170
239
|
headers: { Authorization: `Bearer ${accessToken}` },
|
|
171
240
|
});
|
|
172
241
|
|
|
242
|
+
winston.info(`${LOG_PREFIX} Userinfo response status=%d`, response.status);
|
|
243
|
+
|
|
173
244
|
if (!response.ok) {
|
|
245
|
+
const body = await response.text();
|
|
246
|
+
winston.error(`${LOG_PREFIX} Userinfo error: %s`, body);
|
|
174
247
|
return done(new Error('Kullanıcı bilgisi alınamadı'));
|
|
175
248
|
}
|
|
176
249
|
|
|
177
250
|
const biogrenciUser = await response.json();
|
|
251
|
+
winston.info(`${LOG_PREFIX} Userinfo: sub=%s email=%s name=%s verified=%s`,
|
|
252
|
+
biogrenciUser.sub,
|
|
253
|
+
biogrenciUser.email,
|
|
254
|
+
biogrenciUser.name || biogrenciUser.first_name,
|
|
255
|
+
biogrenciUser.student_verified
|
|
256
|
+
);
|
|
178
257
|
|
|
179
258
|
const handleUser = async function (uid) {
|
|
259
|
+
winston.info(`${LOG_PREFIX} handleUser uid=%s biogrenciId=%s`, uid, biogrenciUser.sub);
|
|
260
|
+
|
|
180
261
|
// Store access/refresh tokens
|
|
181
262
|
await db.setObject(`biogrenci:uid:${uid}`, {
|
|
182
263
|
accessToken,
|
|
@@ -191,14 +272,13 @@ plugin.getStrategy = async function (strategies) {
|
|
|
191
272
|
.filter(Boolean)
|
|
192
273
|
.join(' - ');
|
|
193
274
|
await user.setUserField(uid, 'biogrenci_education', eduString);
|
|
275
|
+
winston.info(`${LOG_PREFIX} Saved education: %s`, eduString);
|
|
194
276
|
}
|
|
195
277
|
|
|
196
278
|
if (biogrenciUser.student_verified) {
|
|
197
279
|
await user.setUserField(uid, 'biogrenci_verified', true);
|
|
198
|
-
}
|
|
199
280
|
|
|
200
|
-
|
|
201
|
-
if (biogrenciUser.student_verified) {
|
|
281
|
+
// Add verified students to a group
|
|
202
282
|
const groupExists = await groups.exists('Doğrulanmış Öğrenciler');
|
|
203
283
|
if (!groupExists) {
|
|
204
284
|
await groups.create({
|
|
@@ -208,8 +288,10 @@ plugin.getStrategy = async function (strategies) {
|
|
|
208
288
|
private: 1,
|
|
209
289
|
disableJoinRequests: 1,
|
|
210
290
|
});
|
|
291
|
+
winston.info(`${LOG_PREFIX} Created "Doğrulanmış Öğrenciler" group`);
|
|
211
292
|
}
|
|
212
293
|
await groups.join('Doğrulanmış Öğrenciler', uid);
|
|
294
|
+
winston.info(`${LOG_PREFIX} User uid=%s added to verified group`, uid);
|
|
213
295
|
}
|
|
214
296
|
|
|
215
297
|
done(null, uid);
|
|
@@ -218,11 +300,13 @@ plugin.getStrategy = async function (strategies) {
|
|
|
218
300
|
// Check if user already linked
|
|
219
301
|
const existingUid = await plugin.getUidByBiogrenciId(biogrenciUser.sub);
|
|
220
302
|
if (existingUid) {
|
|
303
|
+
winston.info(`${LOG_PREFIX} Found existing linked user uid=%s`, existingUid);
|
|
221
304
|
return handleUser(existingUid);
|
|
222
305
|
}
|
|
223
306
|
|
|
224
307
|
// Check if logged-in user wants to link account
|
|
225
308
|
if (req.uid) {
|
|
309
|
+
winston.info(`${LOG_PREFIX} Linking to logged-in user uid=%s`, req.uid);
|
|
226
310
|
await plugin.linkAccount(req.uid, biogrenciUser.sub);
|
|
227
311
|
return handleUser(req.uid);
|
|
228
312
|
}
|
|
@@ -231,30 +315,39 @@ plugin.getStrategy = async function (strategies) {
|
|
|
231
315
|
if (biogrenciUser.email) {
|
|
232
316
|
const existingEmailUid = await user.getUidByEmail(biogrenciUser.email);
|
|
233
317
|
if (existingEmailUid) {
|
|
318
|
+
winston.info(`${LOG_PREFIX} Found user by email uid=%s`, existingEmailUid);
|
|
234
319
|
await plugin.linkAccount(existingEmailUid, biogrenciUser.sub);
|
|
235
320
|
return handleUser(existingEmailUid);
|
|
236
321
|
}
|
|
237
322
|
}
|
|
238
323
|
|
|
239
324
|
// Create new user
|
|
325
|
+
const username = biogrenciUser.first_name
|
|
326
|
+
? `${biogrenciUser.first_name}${biogrenciUser.last_name ? '_' + biogrenciUser.last_name : ''}`
|
|
327
|
+
: `biogrenci_${biogrenciUser.sub}`;
|
|
328
|
+
|
|
329
|
+
winston.info(`${LOG_PREFIX} Creating new user: username=%s email=%s`, username, biogrenciUser.email);
|
|
330
|
+
|
|
240
331
|
const newUid = await user.create({
|
|
241
|
-
username:
|
|
242
|
-
? `${biogrenciUser.first_name}${biogrenciUser.last_name ? '_' + biogrenciUser.last_name : ''}`
|
|
243
|
-
: `biogrenci_${biogrenciUser.sub}`,
|
|
332
|
+
username: username,
|
|
244
333
|
email: biogrenciUser.email || undefined,
|
|
245
334
|
fullname: biogrenciUser.name || undefined,
|
|
246
335
|
});
|
|
247
336
|
|
|
337
|
+
winston.info(`${LOG_PREFIX} Created user uid=%s`, newUid);
|
|
338
|
+
|
|
248
339
|
await plugin.linkAccount(newUid, biogrenciUser.sub);
|
|
249
340
|
|
|
250
341
|
// Set avatar if available
|
|
251
342
|
if (biogrenciUser.avatar) {
|
|
252
343
|
await user.setUserField(newUid, 'picture', biogrenciUser.avatar);
|
|
253
344
|
await user.setUserField(newUid, 'uploadedpicture', biogrenciUser.avatar);
|
|
345
|
+
winston.info(`${LOG_PREFIX} Set avatar for uid=%s`, newUid);
|
|
254
346
|
}
|
|
255
347
|
|
|
256
348
|
handleUser(newUid);
|
|
257
349
|
} catch (err) {
|
|
350
|
+
winston.error(`${LOG_PREFIX} OAuth2 callback error: %s\n%s`, err.message, err.stack);
|
|
258
351
|
done(err);
|
|
259
352
|
}
|
|
260
353
|
},
|
|
@@ -265,6 +358,7 @@ plugin.getStrategy = async function (strategies) {
|
|
|
265
358
|
};
|
|
266
359
|
|
|
267
360
|
passport.use(constants.name, strategy);
|
|
361
|
+
winston.info(`${LOG_PREFIX} Passport strategy "%s" registered`, constants.name);
|
|
268
362
|
|
|
269
363
|
strategies.push({
|
|
270
364
|
name: constants.name,
|
|
@@ -276,15 +370,21 @@ plugin.getStrategy = async function (strategies) {
|
|
|
276
370
|
scope: constants.scope,
|
|
277
371
|
});
|
|
278
372
|
|
|
373
|
+
winston.info(`${LOG_PREFIX} Strategy added to list. Total strategies: %d`, strategies.length);
|
|
279
374
|
return strategies;
|
|
280
375
|
};
|
|
281
376
|
|
|
282
377
|
plugin.listStrategy = async function (strategies) {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
378
|
+
if (plugin.settings.clientId && plugin.settings.clientSecret) {
|
|
379
|
+
strategies.push({
|
|
380
|
+
name: constants.name,
|
|
381
|
+
displayName: constants.displayName,
|
|
382
|
+
icon: constants.icon,
|
|
383
|
+
});
|
|
384
|
+
winston.verbose(`${LOG_PREFIX} listStrategy: added to list`);
|
|
385
|
+
} else {
|
|
386
|
+
winston.warn(`${LOG_PREFIX} listStrategy: skipped, no credentials`);
|
|
387
|
+
}
|
|
288
388
|
return strategies;
|
|
289
389
|
};
|
|
290
390
|
|
|
@@ -317,6 +417,7 @@ plugin.addCustomFields = async function (data) {
|
|
|
317
417
|
};
|
|
318
418
|
|
|
319
419
|
plugin.linkAccount = async function (uid, biogrenciId) {
|
|
420
|
+
winston.info(`${LOG_PREFIX} Linking uid=%s to biogrenciId=%s`, uid, biogrenciId);
|
|
320
421
|
await db.setObjectField('biogrenci:id', biogrenciId, uid);
|
|
321
422
|
await db.setObjectField(`user:${uid}:biogrenci`, 'biogrenciId', biogrenciId);
|
|
322
423
|
};
|
package/package.json
CHANGED
package/static/lib/admin.js
CHANGED
|
@@ -4,23 +4,38 @@ define('admin/plugins/sso-biogrenci', ['settings'], function (Settings) {
|
|
|
4
4
|
var ACP = {};
|
|
5
5
|
|
|
6
6
|
ACP.init = function () {
|
|
7
|
-
|
|
7
|
+
console.log('[sso-biogrenci] Admin page init');
|
|
8
|
+
|
|
9
|
+
var $form = $('.sso-biogrenci-settings');
|
|
10
|
+
console.log('[sso-biogrenci] Form element found:', $form.length > 0);
|
|
11
|
+
console.log('[sso-biogrenci] Form inputs:', $form.find('input').length);
|
|
12
|
+
|
|
13
|
+
Settings.load('sso-biogrenci', $form, function () {
|
|
14
|
+
console.log('[sso-biogrenci] Settings loaded from DB');
|
|
15
|
+
console.log('[sso-biogrenci] clientId value:', $('#clientId').val() ? 'set (' + $('#clientId').val().substring(0, 8) + '...)' : '(empty)');
|
|
16
|
+
console.log('[sso-biogrenci] clientSecret value:', $('#clientSecret').val() ? 'set (hidden)' : '(empty)');
|
|
17
|
+
});
|
|
8
18
|
|
|
9
19
|
$('#save').on('click', function () {
|
|
10
|
-
|
|
20
|
+
console.log('[sso-biogrenci] Save clicked');
|
|
21
|
+
console.log('[sso-biogrenci] Saving clientId:', $('#clientId').val() ? 'set' : '(empty)');
|
|
22
|
+
console.log('[sso-biogrenci] Saving clientSecret:', $('#clientSecret').val() ? 'set' : '(empty)');
|
|
23
|
+
|
|
24
|
+
Settings.save('sso-biogrenci', $form, function () {
|
|
25
|
+
console.log('[sso-biogrenci] Settings saved successfully');
|
|
11
26
|
app.alertSuccess('Ayarlar kaydedildi!');
|
|
12
27
|
});
|
|
13
28
|
});
|
|
14
29
|
|
|
15
30
|
$('#toggleSecret').on('click', function () {
|
|
16
|
-
var input = $('#clientSecret');
|
|
17
|
-
var icon = $(this).find('i');
|
|
18
|
-
if (input.attr('type') === 'password') {
|
|
19
|
-
input.attr('type', 'text');
|
|
20
|
-
icon.removeClass('fa-eye').addClass('fa-eye-slash');
|
|
31
|
+
var $input = $('#clientSecret');
|
|
32
|
+
var $icon = $(this).find('i');
|
|
33
|
+
if ($input.attr('type') === 'password') {
|
|
34
|
+
$input.attr('type', 'text');
|
|
35
|
+
$icon.removeClass('fa-eye').addClass('fa-eye-slash');
|
|
21
36
|
} else {
|
|
22
|
-
input.attr('type', 'password');
|
|
23
|
-
icon.removeClass('fa-eye-slash').addClass('fa-eye');
|
|
37
|
+
$input.attr('type', 'password');
|
|
38
|
+
$icon.removeClass('fa-eye-slash').addClass('fa-eye');
|
|
24
39
|
}
|
|
25
40
|
});
|
|
26
41
|
};
|
|
@@ -10,6 +10,7 @@ define('forum/biogrenci-firsatlar', ['alerts'], function (alerts) {
|
|
|
10
10
|
var searchTimeout = null;
|
|
11
11
|
|
|
12
12
|
Page.init = function () {
|
|
13
|
+
console.log('[sso-biogrenci] Firsatlar page init');
|
|
13
14
|
loadOpportunities();
|
|
14
15
|
|
|
15
16
|
// Filter buttons
|
|
@@ -18,6 +19,7 @@ define('forum/biogrenci-firsatlar', ['alerts'], function (alerts) {
|
|
|
18
19
|
$(this).addClass('active');
|
|
19
20
|
currentType = $(this).attr('data-type');
|
|
20
21
|
currentPage = 1;
|
|
22
|
+
console.log('[sso-biogrenci] Filter changed: type=%s', currentType);
|
|
21
23
|
loadOpportunities();
|
|
22
24
|
});
|
|
23
25
|
|
|
@@ -25,6 +27,7 @@ define('forum/biogrenci-firsatlar', ['alerts'], function (alerts) {
|
|
|
25
27
|
$('#biogrenci-sort').on('change', function () {
|
|
26
28
|
currentSort = $(this).val();
|
|
27
29
|
currentPage = 1;
|
|
30
|
+
console.log('[sso-biogrenci] Sort changed: %s', currentSort);
|
|
28
31
|
loadOpportunities();
|
|
29
32
|
});
|
|
30
33
|
|
|
@@ -35,6 +38,7 @@ define('forum/biogrenci-firsatlar', ['alerts'], function (alerts) {
|
|
|
35
38
|
searchTimeout = setTimeout(function () {
|
|
36
39
|
currentSearch = val;
|
|
37
40
|
currentPage = 1;
|
|
41
|
+
console.log('[sso-biogrenci] Search: %s', currentSearch);
|
|
38
42
|
loadOpportunities();
|
|
39
43
|
}, 400);
|
|
40
44
|
});
|
|
@@ -70,10 +74,38 @@ define('forum/biogrenci-firsatlar', ['alerts'], function (alerts) {
|
|
|
70
74
|
if (currentType) params.set('type', currentType);
|
|
71
75
|
if (currentSearch) params.set('search', currentSearch);
|
|
72
76
|
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
var url = config.relative_path + '/api/biogrenci/firsatlar?' + params.toString();
|
|
78
|
+
console.log('[sso-biogrenci] Fetching opportunities: %s', url);
|
|
79
|
+
|
|
80
|
+
fetch(url)
|
|
81
|
+
.then(function (r) {
|
|
82
|
+
console.log('[sso-biogrenci] API response status: %d', r.status);
|
|
83
|
+
return r.json();
|
|
84
|
+
})
|
|
75
85
|
.then(function (res) {
|
|
76
|
-
|
|
86
|
+
console.log('[sso-biogrenci] API response:', JSON.stringify(res).substring(0, 500));
|
|
87
|
+
console.log('[sso-biogrenci] Response keys:', Object.keys(res));
|
|
88
|
+
|
|
89
|
+
if (res.error) {
|
|
90
|
+
console.error('[sso-biogrenci] API error:', res.error);
|
|
91
|
+
$list.html(
|
|
92
|
+
'<div class="biogrenci-empty biogrenci-error">' +
|
|
93
|
+
'<i class="fa fa-exclamation-triangle fa-3x"></i>' +
|
|
94
|
+
'<h4>Fırsatlar yüklenirken hata oluştu</h4>' +
|
|
95
|
+
'<p>' + res.error + '</p>' +
|
|
96
|
+
'</div>'
|
|
97
|
+
);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
var items = res.data || res.items || res;
|
|
102
|
+
if (Array.isArray(res) && res.length) {
|
|
103
|
+
items = res;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
console.log('[sso-biogrenci] Items count: %d, isArray: %s', items ? items.length : 0, Array.isArray(items));
|
|
107
|
+
|
|
108
|
+
if (!items || !items.length) {
|
|
77
109
|
$list.html(
|
|
78
110
|
'<div class="biogrenci-empty">' +
|
|
79
111
|
'<i class="fa fa-search fa-3x"></i>' +
|
|
@@ -84,15 +116,17 @@ define('forum/biogrenci-firsatlar', ['alerts'], function (alerts) {
|
|
|
84
116
|
$('#biogrenci-pagination').hide();
|
|
85
117
|
return;
|
|
86
118
|
}
|
|
87
|
-
|
|
119
|
+
|
|
120
|
+
renderOpportunities(items);
|
|
88
121
|
renderPagination(res.meta || {});
|
|
89
122
|
})
|
|
90
|
-
.catch(function () {
|
|
123
|
+
.catch(function (err) {
|
|
124
|
+
console.error('[sso-biogrenci] Fetch error:', err);
|
|
91
125
|
$list.html(
|
|
92
126
|
'<div class="biogrenci-empty biogrenci-error">' +
|
|
93
127
|
'<i class="fa fa-exclamation-triangle fa-3x"></i>' +
|
|
94
128
|
'<h4>Fırsatlar yüklenirken hata oluştu</h4>' +
|
|
95
|
-
'<p>
|
|
129
|
+
'<p>' + err.message + '</p>' +
|
|
96
130
|
'</div>'
|
|
97
131
|
);
|
|
98
132
|
});
|
|
@@ -126,7 +160,6 @@ define('forum/biogrenci-firsatlar', ['alerts'], function (alerts) {
|
|
|
126
160
|
|
|
127
161
|
$list.html(html);
|
|
128
162
|
|
|
129
|
-
// Bind claim buttons
|
|
130
163
|
$list.find('.biogrenci-claim-btn').on('click', function () {
|
|
131
164
|
claimOpportunity($(this));
|
|
132
165
|
});
|
|
@@ -148,6 +181,7 @@ define('forum/biogrenci-firsatlar', ['alerts'], function (alerts) {
|
|
|
148
181
|
function claimOpportunity($btn) {
|
|
149
182
|
var id = $btn.attr('data-id');
|
|
150
183
|
$btn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Alınıyor...');
|
|
184
|
+
console.log('[sso-biogrenci] Claiming opportunity id=%s', id);
|
|
151
185
|
|
|
152
186
|
fetch(config.relative_path + '/api/biogrenci/firsatlar/' + id + '/claim', {
|
|
153
187
|
method: 'POST',
|
|
@@ -158,20 +192,23 @@ define('forum/biogrenci-firsatlar', ['alerts'], function (alerts) {
|
|
|
158
192
|
})
|
|
159
193
|
.then(function (r) { return r.json(); })
|
|
160
194
|
.then(function (res) {
|
|
195
|
+
console.log('[sso-biogrenci] Claim response:', res);
|
|
161
196
|
if (res.error) {
|
|
162
197
|
alerts.error(res.error);
|
|
163
198
|
$btn.prop('disabled', false).html('<i class="fa fa-hand-pointer-o"></i> Fırsatı Al');
|
|
164
199
|
return;
|
|
165
200
|
}
|
|
166
|
-
|
|
201
|
+
|
|
202
|
+
var data = res.data || res;
|
|
203
|
+
if (data.coupon_code) {
|
|
167
204
|
$btn.replaceWith(
|
|
168
205
|
'<div class="biogrenci-coupon-result">' +
|
|
169
|
-
'<code class="biogrenci-coupon-code">' +
|
|
170
|
-
'<button class="btn btn-sm biogrenci-copy-btn" data-code="' +
|
|
206
|
+
'<code class="biogrenci-coupon-code">' + data.coupon_code + '</code>' +
|
|
207
|
+
'<button class="btn btn-sm biogrenci-copy-btn" data-code="' + data.coupon_code + '">' +
|
|
171
208
|
'<i class="fa fa-copy"></i>' +
|
|
172
209
|
'</button>' +
|
|
173
|
-
(
|
|
174
|
-
? '<a href="' +
|
|
210
|
+
(data.redirect_url
|
|
211
|
+
? '<a href="' + data.redirect_url + '" target="_blank" rel="noopener" class="btn btn-sm biogrenci-go-btn">Siteye Git <i class="fa fa-external-link"></i></a>'
|
|
175
212
|
: '') +
|
|
176
213
|
'</div>'
|
|
177
214
|
);
|
|
@@ -179,14 +216,15 @@ define('forum/biogrenci-firsatlar', ['alerts'], function (alerts) {
|
|
|
179
216
|
navigator.clipboard.writeText($(this).attr('data-code'));
|
|
180
217
|
alerts.success('Kopyalandı!');
|
|
181
218
|
});
|
|
182
|
-
} else if (
|
|
183
|
-
$btn.replaceWith('<div class="biogrenci-qr-result">' +
|
|
184
|
-
} else if (
|
|
185
|
-
window.open(
|
|
219
|
+
} else if (data.qr_code) {
|
|
220
|
+
$btn.replaceWith('<div class="biogrenci-qr-result">' + data.qr_code + '</div>');
|
|
221
|
+
} else if (data.redirect_url) {
|
|
222
|
+
window.open(data.redirect_url, '_blank');
|
|
186
223
|
$btn.html('<i class="fa fa-check"></i> Açıldı').addClass('claimed');
|
|
187
224
|
}
|
|
188
225
|
})
|
|
189
|
-
.catch(function () {
|
|
226
|
+
.catch(function (err) {
|
|
227
|
+
console.error('[sso-biogrenci] Claim error:', err);
|
|
190
228
|
alerts.error('Bir hata oluştu');
|
|
191
229
|
$btn.prop('disabled', false).html('<i class="fa fa-hand-pointer-o"></i> Fırsatı Al');
|
|
192
230
|
});
|