nodebb-plugin-sso-biogrenci 1.0.0 → 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.
@@ -0,0 +1,10 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
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
+ "WebFetch(domain:raw.githubusercontent.com)",
6
+ "Bash(xargs grep:*)",
7
+ "WebFetch(domain:biogrenci.com)"
8
+ ]
9
+ }
10
+ }
package/image.png ADDED
Binary file
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 response = await fetch(`${constants.partnerAPIBase}/opportunities/${req.params.id}/claim`, {
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
- const data = await db.getObject(`biogrenci:uid:${req.uid}`);
78
- if (data && data.biogrenciId) {
79
- const education = await user.getUserField(req.uid, 'biogrenci_education');
80
- const verified = await user.getUserField(req.uid, 'biogrenci_verified');
81
- return res.json({
82
- linked: true,
83
- biogrenciId: data.biogrenciId,
84
- education: education || null,
85
- verified: !!verified,
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,25 +126,44 @@ 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
- const settings = await meta.settings.get('sso-biogrenci');
113
- if (settings.clientId) plugin.settings.clientId = settings.clientId;
114
- if (settings.clientSecret) plugin.settings.clientSecret = settings.clientSecret;
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) {
157
+ const callbackURL = nconf.get('url') + '/auth/biogrenci/callback';
158
+ winston.verbose(`${LOG_PREFIX} Rendering admin page, callbackURL=%s`, callbackURL);
118
159
  res.render('admin/plugins/sso-biogrenci', {
119
160
  title: "bi'öğrenci SSO",
161
+ callbackURL: callbackURL,
120
162
  });
121
163
  }
122
164
 
123
165
  async function renderFirsatlar(req, res) {
166
+ winston.verbose(`${LOG_PREFIX} Rendering firsatlar page, uid=%s`, req.uid);
124
167
  res.render('biogrenci-firsatlar', {
125
168
  title: 'Öğrenci Fırsatları',
126
169
  uid: req.uid || 0,
@@ -137,19 +180,42 @@ async function fetchOpportunities(query) {
137
180
  params.set('page', query.page || 1);
138
181
  params.set('per_page', query.per_page || 20);
139
182
 
140
- const response = await fetch(`${constants.partnerAPIBase}/opportunities?${params.toString()}`);
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
+
141
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);
142
198
  throw new Error(`Partner API error: ${response.status}`);
143
199
  }
144
- return response.json();
200
+
201
+ const data = await response.json();
202
+ winston.info(`${LOG_PREFIX} Partner API data keys=%j`, Object.keys(data));
203
+ return data;
145
204
  }
146
205
 
147
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
+
148
212
  if (!plugin.settings.clientId || !plugin.settings.clientSecret) {
213
+ winston.warn(`${LOG_PREFIX} Missing credentials, skipping strategy registration`);
149
214
  return strategies;
150
215
  }
151
216
 
152
217
  const callbackURL = nconf.get('url') + '/auth/biogrenci/callback';
218
+ winston.info(`${LOG_PREFIX} Registering OAuth2 strategy, callbackURL=%s`, callbackURL);
153
219
 
154
220
  const strategy = new OAuth2Strategy(
155
221
  {
@@ -162,19 +228,36 @@ plugin.getStrategy = async function (strategies) {
162
228
  passReqToCallback: true,
163
229
  },
164
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
+ );
165
235
  try {
166
236
  // Fetch user info from bi'ogrenci
237
+ winston.info(`${LOG_PREFIX} Fetching userinfo from %s`, constants.userInfoURL);
167
238
  const response = await fetch(constants.userInfoURL, {
168
239
  headers: { Authorization: `Bearer ${accessToken}` },
169
240
  });
170
241
 
242
+ winston.info(`${LOG_PREFIX} Userinfo response status=%d`, response.status);
243
+
171
244
  if (!response.ok) {
245
+ const body = await response.text();
246
+ winston.error(`${LOG_PREFIX} Userinfo error: %s`, body);
172
247
  return done(new Error('Kullanıcı bilgisi alınamadı'));
173
248
  }
174
249
 
175
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
+ );
176
257
 
177
258
  const handleUser = async function (uid) {
259
+ winston.info(`${LOG_PREFIX} handleUser uid=%s biogrenciId=%s`, uid, biogrenciUser.sub);
260
+
178
261
  // Store access/refresh tokens
179
262
  await db.setObject(`biogrenci:uid:${uid}`, {
180
263
  accessToken,
@@ -189,14 +272,13 @@ plugin.getStrategy = async function (strategies) {
189
272
  .filter(Boolean)
190
273
  .join(' - ');
191
274
  await user.setUserField(uid, 'biogrenci_education', eduString);
275
+ winston.info(`${LOG_PREFIX} Saved education: %s`, eduString);
192
276
  }
193
277
 
194
278
  if (biogrenciUser.student_verified) {
195
279
  await user.setUserField(uid, 'biogrenci_verified', true);
196
- }
197
280
 
198
- // Add verified students to a group
199
- if (biogrenciUser.student_verified) {
281
+ // Add verified students to a group
200
282
  const groupExists = await groups.exists('Doğrulanmış Öğrenciler');
201
283
  if (!groupExists) {
202
284
  await groups.create({
@@ -206,8 +288,10 @@ plugin.getStrategy = async function (strategies) {
206
288
  private: 1,
207
289
  disableJoinRequests: 1,
208
290
  });
291
+ winston.info(`${LOG_PREFIX} Created "Doğrulanmış Öğrenciler" group`);
209
292
  }
210
293
  await groups.join('Doğrulanmış Öğrenciler', uid);
294
+ winston.info(`${LOG_PREFIX} User uid=%s added to verified group`, uid);
211
295
  }
212
296
 
213
297
  done(null, uid);
@@ -216,11 +300,13 @@ plugin.getStrategy = async function (strategies) {
216
300
  // Check if user already linked
217
301
  const existingUid = await plugin.getUidByBiogrenciId(biogrenciUser.sub);
218
302
  if (existingUid) {
303
+ winston.info(`${LOG_PREFIX} Found existing linked user uid=%s`, existingUid);
219
304
  return handleUser(existingUid);
220
305
  }
221
306
 
222
307
  // Check if logged-in user wants to link account
223
308
  if (req.uid) {
309
+ winston.info(`${LOG_PREFIX} Linking to logged-in user uid=%s`, req.uid);
224
310
  await plugin.linkAccount(req.uid, biogrenciUser.sub);
225
311
  return handleUser(req.uid);
226
312
  }
@@ -229,30 +315,39 @@ plugin.getStrategy = async function (strategies) {
229
315
  if (biogrenciUser.email) {
230
316
  const existingEmailUid = await user.getUidByEmail(biogrenciUser.email);
231
317
  if (existingEmailUid) {
318
+ winston.info(`${LOG_PREFIX} Found user by email uid=%s`, existingEmailUid);
232
319
  await plugin.linkAccount(existingEmailUid, biogrenciUser.sub);
233
320
  return handleUser(existingEmailUid);
234
321
  }
235
322
  }
236
323
 
237
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
+
238
331
  const newUid = await user.create({
239
- username: biogrenciUser.first_name
240
- ? `${biogrenciUser.first_name}${biogrenciUser.last_name ? '_' + biogrenciUser.last_name : ''}`
241
- : `biogrenci_${biogrenciUser.sub}`,
332
+ username: username,
242
333
  email: biogrenciUser.email || undefined,
243
334
  fullname: biogrenciUser.name || undefined,
244
335
  });
245
336
 
337
+ winston.info(`${LOG_PREFIX} Created user uid=%s`, newUid);
338
+
246
339
  await plugin.linkAccount(newUid, biogrenciUser.sub);
247
340
 
248
341
  // Set avatar if available
249
342
  if (biogrenciUser.avatar) {
250
343
  await user.setUserField(newUid, 'picture', biogrenciUser.avatar);
251
344
  await user.setUserField(newUid, 'uploadedpicture', biogrenciUser.avatar);
345
+ winston.info(`${LOG_PREFIX} Set avatar for uid=%s`, newUid);
252
346
  }
253
347
 
254
348
  handleUser(newUid);
255
349
  } catch (err) {
350
+ winston.error(`${LOG_PREFIX} OAuth2 callback error: %s\n%s`, err.message, err.stack);
256
351
  done(err);
257
352
  }
258
353
  },
@@ -263,6 +358,7 @@ plugin.getStrategy = async function (strategies) {
263
358
  };
264
359
 
265
360
  passport.use(constants.name, strategy);
361
+ winston.info(`${LOG_PREFIX} Passport strategy "%s" registered`, constants.name);
266
362
 
267
363
  strategies.push({
268
364
  name: constants.name,
@@ -274,15 +370,21 @@ plugin.getStrategy = async function (strategies) {
274
370
  scope: constants.scope,
275
371
  });
276
372
 
373
+ winston.info(`${LOG_PREFIX} Strategy added to list. Total strategies: %d`, strategies.length);
277
374
  return strategies;
278
375
  };
279
376
 
280
377
  plugin.listStrategy = async function (strategies) {
281
- strategies.push({
282
- name: constants.name,
283
- displayName: constants.displayName,
284
- icon: constants.icon,
285
- });
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
+ }
286
388
  return strategies;
287
389
  };
288
390
 
@@ -315,6 +417,7 @@ plugin.addCustomFields = async function (data) {
315
417
  };
316
418
 
317
419
  plugin.linkAccount = async function (uid, biogrenciId) {
420
+ winston.info(`${LOG_PREFIX} Linking uid=%s to biogrenciId=%s`, uid, biogrenciId);
318
421
  await db.setObjectField('biogrenci:id', biogrenciId, uid);
319
422
  await db.setObjectField(`user:${uid}:biogrenci`, 'biogrenciId', biogrenciId);
320
423
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-sso-biogrenci",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "bi'öğrenci OAuth2 SSO login & öğrenci indirimleri for NodeBB",
5
5
  "main": "library.js",
6
6
  "keywords": [
@@ -11,10 +11,10 @@
11
11
  "oauth2"
12
12
  ],
13
13
  "nbbpm": {
14
- "compatibility": "^3.2.0"
14
+ "compatibility": "^3.2.0 || ^4.0.0"
15
15
  },
16
16
  "dependencies": {
17
17
  "passport-oauth2": "^1.8.0"
18
18
  },
19
19
  "license": "MIT"
20
- }
20
+ }
package/plugin.json CHANGED
@@ -6,6 +6,11 @@
6
6
  "static": "./static"
7
7
  },
8
8
  "less": ["static/style.less"],
9
+ "modules": {
10
+ "../admin/plugins/sso-biogrenci.js": "static/lib/admin.js",
11
+ "../client/biogrenci-firsatlar.js": "static/lib/biogrenci-firsatlar.js",
12
+ "../client/account/biogrenci.js": "static/lib/account-biogrenci.js"
13
+ },
9
14
  "hooks": [
10
15
  { "hook": "filter:auth.init", "method": "getStrategy" },
11
16
  { "hook": "filter:auth.list", "method": "listStrategy" },
@@ -0,0 +1,72 @@
1
+ 'use strict';
2
+
3
+ define('forum/account/biogrenci', ['alerts'], function (alerts) {
4
+ var AccountPage = {};
5
+
6
+ AccountPage.init = function () {
7
+ loadStatus();
8
+ };
9
+
10
+ function loadStatus() {
11
+ fetch(config.relative_path + '/api/biogrenci/status')
12
+ .then(function (r) { return r.json(); })
13
+ .then(function (data) {
14
+ var $el = $('#biogrenci-status');
15
+ if (data.linked) {
16
+ $el.html(
17
+ '<div class="biogrenci-linked">' +
18
+ '<div class="biogrenci-linked-badge">' +
19
+ '<i class="fa fa-check-circle"></i> Hesap Bağlı' +
20
+ '</div>' +
21
+ (data.verified
22
+ ? '<div class="biogrenci-verified-badge"><i class="fa fa-shield"></i> Doğrulanmış Öğrenci</div>'
23
+ : '') +
24
+ (data.education
25
+ ? '<div class="biogrenci-education"><i class="fa fa-university"></i> ' + data.education + '</div>'
26
+ : '') +
27
+ '<hr/>' +
28
+ '<button id="biogrenci-unlink" class="btn btn-danger btn-sm">' +
29
+ '<i class="fa fa-unlink"></i> Bağlantıyı Kaldır' +
30
+ '</button>' +
31
+ '</div>'
32
+ );
33
+
34
+ $('#biogrenci-unlink').on('click', unlinkAccount);
35
+ } else {
36
+ $el.html(
37
+ '<div class="biogrenci-not-linked">' +
38
+ '<p>bi\'öğrenci hesabınız henüz bağlı değil.</p>' +
39
+ '<p class="text-muted">Hesabınızı bağlayarak öğrenci doğrulaması yapabilir ve fırsatlardan yararlanabilirsiniz.</p>' +
40
+ '<a href="' + config.relative_path + '/auth/biogrenci" class="btn btn-primary">' +
41
+ '<i class="fa fa-graduation-cap"></i> bi\'öğrenci Hesabını Bağla' +
42
+ '</a>' +
43
+ '</div>'
44
+ );
45
+ }
46
+ });
47
+ }
48
+
49
+ function unlinkAccount() {
50
+ bootbox.confirm("bi'öğrenci hesap bağlantısını kaldırmak istediğinize emin misiniz?", function (ok) {
51
+ if (!ok) return;
52
+ fetch(config.relative_path + '/api/biogrenci/unlink', {
53
+ method: 'POST',
54
+ headers: {
55
+ 'x-csrf-token': config.csrf_token,
56
+ 'Content-Type': 'application/json',
57
+ },
58
+ })
59
+ .then(function (r) { return r.json(); })
60
+ .then(function (res) {
61
+ if (res.success) {
62
+ alerts.success("bi'öğrenci bağlantısı kaldırıldı");
63
+ loadStatus();
64
+ } else {
65
+ alerts.error(res.error || 'Bir hata oluştu');
66
+ }
67
+ });
68
+ });
69
+ }
70
+
71
+ return AccountPage;
72
+ });
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+
3
+ define('admin/plugins/sso-biogrenci', ['settings'], function (Settings) {
4
+ var ACP = {};
5
+
6
+ ACP.init = function () {
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
+ });
18
+
19
+ $('#save').on('click', function () {
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');
26
+ app.alertSuccess('Ayarlar kaydedildi!');
27
+ });
28
+ });
29
+
30
+ $('#toggleSecret').on('click', function () {
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');
36
+ } else {
37
+ $input.attr('type', 'password');
38
+ $icon.removeClass('fa-eye-slash').addClass('fa-eye');
39
+ }
40
+ });
41
+ };
42
+
43
+ return ACP;
44
+ });