collavre_notion 0.1.1 → 0.1.3
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.
- checksums.yaml +4 -4
- data/app/controllers/collavre_notion/creatives/notion_integrations_controller.rb +4 -17
- data/app/controllers/collavre_notion/notion_auth_controller.rb +2 -18
- data/app/javascript/collavre_notion.js +32 -86
- data/app/views/collavre_notion/notion_auth/callback_success.html.erb +16 -0
- data/lib/collavre_notion/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 79c6d353c5d4bb7cceebb0f7d4ed7f1f4a3c81be1df39305aa4ecced9a305f75
|
|
4
|
+
data.tar.gz: 49d5d8b36ac8fd0ff3e03d32ff58bb8c5395dbea3cc1974db95b1b4d7a0aeb16
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6a69db91cc2c0694d5925f349c414880fed6d69df2cb4e6a8855228a125fc975b9ae6065ca88700082b2da8c5e999e1fa5d9d199134b781d3704037301c36063
|
|
7
|
+
data.tar.gz: 88c045ced22013630fab5ab674bc6c3e81de16038c51b4d39a42ad23ee0a83f2699609e8dbe873774729d1a92bbf520ba2124d5a7e7bc2b7f720a0979e1841fa
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
module CollavreNotion
|
|
2
2
|
module Creatives
|
|
3
3
|
class NotionIntegrationsController < ApplicationController
|
|
4
|
+
include Collavre::IntegrationSetup
|
|
5
|
+
include Collavre::IntegrationPermission
|
|
6
|
+
|
|
4
7
|
before_action :set_creative
|
|
5
8
|
before_action :ensure_read_permission
|
|
6
9
|
before_action :ensure_admin_permission, only: [ :show, :update ]
|
|
@@ -78,7 +81,7 @@ module CollavreNotion
|
|
|
78
81
|
|
|
79
82
|
def destroy
|
|
80
83
|
unless @creative.has_permission?(Current.user, :write)
|
|
81
|
-
render json: { error:
|
|
84
|
+
render json: { error: integration_forbidden_message }, status: :forbidden
|
|
82
85
|
return
|
|
83
86
|
end
|
|
84
87
|
|
|
@@ -120,22 +123,6 @@ module CollavreNotion
|
|
|
120
123
|
|
|
121
124
|
private
|
|
122
125
|
|
|
123
|
-
def set_creative
|
|
124
|
-
@creative = Collavre::Creative.find(params[:creative_id])
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def ensure_read_permission
|
|
128
|
-
return if @creative.has_permission?(Current.user, :read)
|
|
129
|
-
|
|
130
|
-
render json: { error: "forbidden" }, status: :forbidden
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def ensure_admin_permission
|
|
134
|
-
return if @creative.has_permission?(Current.user, :admin)
|
|
135
|
-
|
|
136
|
-
render json: { error: "forbidden" }, status: :forbidden
|
|
137
|
-
end
|
|
138
|
-
|
|
139
126
|
def linked_page_links(account)
|
|
140
127
|
return CollavreNotion::NotionPageLink.none unless account
|
|
141
128
|
|
|
@@ -22,24 +22,8 @@ module CollavreNotion
|
|
|
22
22
|
# If opened in popup, close it and notify parent window
|
|
23
23
|
if params[:popup] || request.referer&.include?("popup=true") || session[:oauth_popup]
|
|
24
24
|
session.delete(:oauth_popup)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
<html>
|
|
28
|
-
<head><title>Notion Connected</title></head>
|
|
29
|
-
<body>
|
|
30
|
-
<script>
|
|
31
|
-
if (window.opener) {
|
|
32
|
-
window.opener.postMessage({ type: 'notion_oauth_success', connected: true }, '*');
|
|
33
|
-
window.close();
|
|
34
|
-
} else {
|
|
35
|
-
window.location.href = '#{collavre.creatives_path}';
|
|
36
|
-
}
|
|
37
|
-
</script>
|
|
38
|
-
<p>#{I18n.t("collavre_notion.notion_auth.connected")}</p>
|
|
39
|
-
<p>This window should close automatically. If not, you can close it manually.</p>
|
|
40
|
-
</body>
|
|
41
|
-
</html>
|
|
42
|
-
HTML
|
|
25
|
+
@fallback_path = collavre.creatives_path
|
|
26
|
+
render template: "collavre_notion/notion_auth/callback_success", layout: false
|
|
43
27
|
else
|
|
44
28
|
redirect_to collavre.creatives_path, notice: I18n.t("collavre_notion.notion_auth.connected")
|
|
45
29
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { csrfToken, showError, clearError, updateStepVisibility, openOAuthPopup, fetchWithCsrf, setupModalClose } from 'collavre/modules/integration_wizard';
|
|
2
|
+
|
|
1
3
|
let notionIntegrationInitialized = false;
|
|
2
4
|
|
|
3
5
|
if (!notionIntegrationInitialized) {
|
|
@@ -43,10 +45,6 @@ if (!notionIntegrationInitialized) {
|
|
|
43
45
|
let exportType = 'new-page';
|
|
44
46
|
let selectedParentPage = null;
|
|
45
47
|
|
|
46
|
-
function csrfToken() {
|
|
47
|
-
return document.querySelector('meta[name="csrf-token"]')?.content;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
48
|
function resetWizard() {
|
|
51
49
|
currentStep = 'connect';
|
|
52
50
|
hasExistingIntegration = false;
|
|
@@ -55,8 +53,7 @@ if (!notionIntegrationInitialized) {
|
|
|
55
53
|
exportType = 'new-page';
|
|
56
54
|
selectedParentPage = null;
|
|
57
55
|
statusEl.textContent = '';
|
|
58
|
-
errorEl
|
|
59
|
-
errorEl.textContent = '';
|
|
56
|
+
clearError(errorEl);
|
|
60
57
|
if (existingContainer) {
|
|
61
58
|
existingContainer.style.display = 'none';
|
|
62
59
|
}
|
|
@@ -74,12 +71,7 @@ if (!notionIntegrationInitialized) {
|
|
|
74
71
|
}
|
|
75
72
|
|
|
76
73
|
function updateStep() {
|
|
77
|
-
['connect', 'workspace', 'summary']
|
|
78
|
-
.forEach(function (step) {
|
|
79
|
-
const el = document.getElementById(`notion-step-${step}`);
|
|
80
|
-
if (!el) return;
|
|
81
|
-
el.style.display = (step === currentStep) ? 'block' : 'none';
|
|
82
|
-
});
|
|
74
|
+
updateStepVisibility(currentStep, ['connect', 'workspace', 'summary'], 'notion-step');
|
|
83
75
|
|
|
84
76
|
if (currentStep === 'connect') {
|
|
85
77
|
prevBtn.style.display = 'none';
|
|
@@ -105,29 +97,13 @@ if (!notionIntegrationInitialized) {
|
|
|
105
97
|
}
|
|
106
98
|
}
|
|
107
99
|
|
|
108
|
-
function showError(message) {
|
|
109
|
-
errorEl.textContent = message;
|
|
110
|
-
errorEl.style.display = 'block';
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function clearError() {
|
|
114
|
-
errorEl.style.display = 'none';
|
|
115
|
-
errorEl.textContent = '';
|
|
116
|
-
}
|
|
117
|
-
|
|
118
100
|
function loadIntegrationStatus() {
|
|
119
101
|
if (!creativeId) return;
|
|
120
102
|
|
|
121
103
|
statusEl.textContent = modal.dataset.loading;
|
|
122
|
-
clearError();
|
|
104
|
+
clearError(errorEl);
|
|
123
105
|
|
|
124
|
-
|
|
125
|
-
method: 'GET',
|
|
126
|
-
headers: {
|
|
127
|
-
'X-CSRF-Token': csrfToken(),
|
|
128
|
-
'Content-Type': 'application/json'
|
|
129
|
-
}
|
|
130
|
-
})
|
|
106
|
+
fetchWithCsrf(`/notion/creatives/${creativeId}/notion_integration`)
|
|
131
107
|
.then(response => response.json())
|
|
132
108
|
.then(data => {
|
|
133
109
|
console.log('Notion integration status:', data);
|
|
@@ -168,7 +144,7 @@ if (!notionIntegrationInitialized) {
|
|
|
168
144
|
.catch(error => {
|
|
169
145
|
console.error('Error loading integration status:', error);
|
|
170
146
|
statusEl.textContent = '';
|
|
171
|
-
showError(modal.dataset.loadFailed);
|
|
147
|
+
showError(errorEl, modal.dataset.loadFailed);
|
|
172
148
|
});
|
|
173
149
|
}
|
|
174
150
|
|
|
@@ -285,13 +261,13 @@ if (!notionIntegrationInitialized) {
|
|
|
285
261
|
|
|
286
262
|
function performExport() {
|
|
287
263
|
if (!creativeId) {
|
|
288
|
-
showError(modal.dataset.noCreative);
|
|
264
|
+
showError(errorEl, modal.dataset.noCreative);
|
|
289
265
|
return;
|
|
290
266
|
}
|
|
291
267
|
|
|
292
268
|
exportBtn.disabled = true;
|
|
293
269
|
exportBtn.textContent = modal.dataset.exporting;
|
|
294
|
-
clearError();
|
|
270
|
+
clearError(errorEl);
|
|
295
271
|
|
|
296
272
|
const requestData = {
|
|
297
273
|
action: 'export'
|
|
@@ -304,13 +280,9 @@ if (!notionIntegrationInitialized) {
|
|
|
304
280
|
console.log('Sending export request:', requestData);
|
|
305
281
|
console.log('Export type:', exportType, 'Selected parent page:', selectedParentPage);
|
|
306
282
|
|
|
307
|
-
|
|
283
|
+
fetchWithCsrf(`/notion/creatives/${creativeId}/notion_integration`, {
|
|
308
284
|
method: 'PATCH',
|
|
309
|
-
|
|
310
|
-
'X-CSRF-Token': csrfToken(),
|
|
311
|
-
'Content-Type': 'application/json'
|
|
312
|
-
},
|
|
313
|
-
body: JSON.stringify(requestData)
|
|
285
|
+
body: requestData
|
|
314
286
|
})
|
|
315
287
|
.then(response => response.json())
|
|
316
288
|
.then(data => {
|
|
@@ -322,12 +294,12 @@ if (!notionIntegrationInitialized) {
|
|
|
322
294
|
resetWizard();
|
|
323
295
|
}, 2000);
|
|
324
296
|
} else {
|
|
325
|
-
showError(data.message || modal.dataset.exportFailed);
|
|
297
|
+
showError(errorEl, data.message || modal.dataset.exportFailed);
|
|
326
298
|
}
|
|
327
299
|
})
|
|
328
300
|
.catch(error => {
|
|
329
301
|
console.error('Export error:', error);
|
|
330
|
-
showError(modal.dataset.exportFailed);
|
|
302
|
+
showError(errorEl, modal.dataset.exportFailed);
|
|
331
303
|
})
|
|
332
304
|
.finally(() => {
|
|
333
305
|
exportBtn.disabled = false;
|
|
@@ -340,15 +312,11 @@ if (!notionIntegrationInitialized) {
|
|
|
340
312
|
|
|
341
313
|
syncBtn.disabled = true;
|
|
342
314
|
syncBtn.textContent = modal.dataset.syncing;
|
|
343
|
-
clearError();
|
|
315
|
+
clearError(errorEl);
|
|
344
316
|
|
|
345
|
-
|
|
317
|
+
fetchWithCsrf(`/notion/creatives/${creativeId}/notion_integration`, {
|
|
346
318
|
method: 'PATCH',
|
|
347
|
-
|
|
348
|
-
'X-CSRF-Token': csrfToken(),
|
|
349
|
-
'Content-Type': 'application/json'
|
|
350
|
-
},
|
|
351
|
-
body: JSON.stringify({ action: 'sync' })
|
|
319
|
+
body: { action: 'sync' }
|
|
352
320
|
})
|
|
353
321
|
.then(response => response.json())
|
|
354
322
|
.then(data => {
|
|
@@ -356,12 +324,12 @@ if (!notionIntegrationInitialized) {
|
|
|
356
324
|
statusEl.textContent = modal.dataset.syncSuccess || 'Sync completed successfully';
|
|
357
325
|
statusEl.style.color = 'green';
|
|
358
326
|
} else {
|
|
359
|
-
showError(data.message || modal.dataset.syncFailed);
|
|
327
|
+
showError(errorEl, data.message || modal.dataset.syncFailed);
|
|
360
328
|
}
|
|
361
329
|
})
|
|
362
330
|
.catch(error => {
|
|
363
331
|
console.error('Sync error:', error);
|
|
364
|
-
showError(modal.dataset.syncFailed);
|
|
332
|
+
showError(errorEl, modal.dataset.syncFailed);
|
|
365
333
|
})
|
|
366
334
|
.finally(() => {
|
|
367
335
|
syncBtn.disabled = false;
|
|
@@ -374,15 +342,9 @@ if (!notionIntegrationInitialized) {
|
|
|
374
342
|
|
|
375
343
|
deleteBtn.disabled = true;
|
|
376
344
|
deleteBtn.textContent = modal.dataset.removing;
|
|
377
|
-
clearError();
|
|
345
|
+
clearError(errorEl);
|
|
378
346
|
|
|
379
|
-
|
|
380
|
-
method: 'DELETE',
|
|
381
|
-
headers: {
|
|
382
|
-
'X-CSRF-Token': csrfToken(),
|
|
383
|
-
'Content-Type': 'application/json'
|
|
384
|
-
}
|
|
385
|
-
})
|
|
347
|
+
fetchWithCsrf(`/notion/creatives/${creativeId}/notion_integration`, { method: 'DELETE' })
|
|
386
348
|
.then(response => response.json())
|
|
387
349
|
.then(data => {
|
|
388
350
|
if (data.success) {
|
|
@@ -393,12 +355,12 @@ if (!notionIntegrationInitialized) {
|
|
|
393
355
|
resetWizard();
|
|
394
356
|
}, 2000);
|
|
395
357
|
} else {
|
|
396
|
-
showError(data.message || modal.dataset.deleteFailed);
|
|
358
|
+
showError(errorEl, data.message || modal.dataset.deleteFailed);
|
|
397
359
|
}
|
|
398
360
|
})
|
|
399
361
|
.catch(error => {
|
|
400
362
|
console.error('Delete error:', error);
|
|
401
|
-
showError(modal.dataset.deleteFailed);
|
|
363
|
+
showError(errorEl, modal.dataset.deleteFailed);
|
|
402
364
|
})
|
|
403
365
|
.finally(() => {
|
|
404
366
|
deleteBtn.disabled = false;
|
|
@@ -418,10 +380,7 @@ if (!notionIntegrationInitialized) {
|
|
|
418
380
|
loadIntegrationStatus();
|
|
419
381
|
});
|
|
420
382
|
|
|
421
|
-
|
|
422
|
-
modal.style.display = 'none';
|
|
423
|
-
resetWizard();
|
|
424
|
-
});
|
|
383
|
+
setupModalClose(modal, closeBtn, resetWizard);
|
|
425
384
|
|
|
426
385
|
// Listen for OAuth success message from popup window
|
|
427
386
|
window.addEventListener('message', function(event) {
|
|
@@ -436,26 +395,19 @@ if (!notionIntegrationInitialized) {
|
|
|
436
395
|
|
|
437
396
|
loginBtn.addEventListener('click', function () {
|
|
438
397
|
console.log('Notion login button clicked');
|
|
439
|
-
const
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
398
|
+
const authWindow = openOAuthPopup('notion-auth-window', {
|
|
399
|
+
width: parseInt(this.dataset.windowWidth) || 600,
|
|
400
|
+
height: parseInt(this.dataset.windowHeight) || 700,
|
|
401
|
+
onClose: function () {
|
|
402
|
+
console.log('Auth window closed, reloading integration status');
|
|
403
|
+
loadIntegrationStatus();
|
|
404
|
+
}
|
|
405
|
+
});
|
|
443
406
|
|
|
444
|
-
const authWindow = window.open('', 'notion-auth-window',
|
|
445
|
-
`width=${width},height=${height},left=${left},top=${top},scrollbars=yes,resizable=yes`);
|
|
446
|
-
|
|
447
407
|
if (authWindow) {
|
|
448
408
|
loginForm.target = 'notion-auth-window';
|
|
449
409
|
loginForm.submit();
|
|
450
410
|
console.log('Auth form submitted to popup window');
|
|
451
|
-
|
|
452
|
-
const checkClosed = setInterval(() => {
|
|
453
|
-
if (authWindow.closed) {
|
|
454
|
-
clearInterval(checkClosed);
|
|
455
|
-
console.log('Auth window closed, reloading integration status');
|
|
456
|
-
setTimeout(() => loadIntegrationStatus(), 1000);
|
|
457
|
-
}
|
|
458
|
-
}, 1000);
|
|
459
411
|
} else {
|
|
460
412
|
loginForm.target = '_blank';
|
|
461
413
|
loginForm.submit();
|
|
@@ -472,7 +424,7 @@ if (!notionIntegrationInitialized) {
|
|
|
472
424
|
});
|
|
473
425
|
|
|
474
426
|
nextBtn.addEventListener('click', function () {
|
|
475
|
-
clearError();
|
|
427
|
+
clearError(errorEl);
|
|
476
428
|
if (currentStep === 'connect') {
|
|
477
429
|
currentStep = 'workspace';
|
|
478
430
|
updateParentPageOptions();
|
|
@@ -501,11 +453,5 @@ if (!notionIntegrationInitialized) {
|
|
|
501
453
|
});
|
|
502
454
|
}
|
|
503
455
|
|
|
504
|
-
modal.addEventListener('click', function (e) {
|
|
505
|
-
if (e.target === modal) {
|
|
506
|
-
modal.style.display = 'none';
|
|
507
|
-
resetWizard();
|
|
508
|
-
}
|
|
509
|
-
});
|
|
510
456
|
});
|
|
511
457
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head><title>Notion Connected</title></head>
|
|
4
|
+
<body>
|
|
5
|
+
<script>
|
|
6
|
+
if (window.opener) {
|
|
7
|
+
window.opener.postMessage({ type: 'notion_oauth_success', connected: true }, window.location.origin);
|
|
8
|
+
window.close();
|
|
9
|
+
} else {
|
|
10
|
+
window.location.href = '<%= @fallback_path %>';
|
|
11
|
+
}
|
|
12
|
+
</script>
|
|
13
|
+
<p><%= t("collavre_notion.notion_auth.connected") %></p>
|
|
14
|
+
<p>This window should close automatically. If not, you can close it manually.</p>
|
|
15
|
+
</body>
|
|
16
|
+
</html>
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: collavre_notion
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Collavre
|
|
@@ -74,6 +74,7 @@ files:
|
|
|
74
74
|
- app/services/collavre_notion/notion_creative_exporter.rb
|
|
75
75
|
- app/services/collavre_notion/notion_service.rb
|
|
76
76
|
- app/views/collavre_notion/integrations/_modal.html.erb
|
|
77
|
+
- app/views/collavre_notion/notion_auth/callback_success.html.erb
|
|
77
78
|
- config/locales/en.yml
|
|
78
79
|
- config/locales/ko.yml
|
|
79
80
|
- config/routes.rb
|