مشكلة CORS عند النشر إلى Discourse من Obsidian

لقد بدأت في استخدام Obsidian للكتابة، لذا فكرت في إنشاء إضافة Obsidian للنشر على منتدى Discourse الخاص بي. من الناحية النظرية، هذا سهل، لكن الاستجابة من محاولتي الأولى كانت:

تم حظر الوصول إلى fetch في 'http://localhost:4200/posts.json' من الأصل 'app://obsidian.md' بواسطة سياسة CORS: استجابة طلب preflight لا تمر عبر فحص التحكم في الوصول: لا يوجد رأس 'Access-Control-Allow-Origin' في المورد المطلوب. إذا كان استجابة غامضة تفي باحتياجاتك، فقم بتعيين وضع الطلب إلى 'no-cors' لجلب المورد مع تعطيل CORS.

يتم إجراء الطلب من العميل، لكن العميل هو جهاز المستخدم. إذا كنت أفهم الأمور بشكل صحيح، فهذا آمن:

import DiscoursePlugin from "./main";
import { TFile } from "obsidian";

export async function publishToDiscourse(
	plugin: DiscoursePlugin,
	activeFile: TFile
): Promise<{ message: string }> {
	try {
		const content = await plugin.app.vault.read(activeFile);
		const baseUrl = plugin.settings.baseUrl;
		const apiKey = plugin.settings.apiKey;

		const headers = new Headers({
			"Content-Type": "application/json",
			"Api-Key": apiKey,
			"Api-Username": "scossar", // this needs to be a setting
		});
		const body = JSON.stringify({
			title: activeFile.name,
			raw: content, // TODO: parse the content to fix internal links
			category: 1, // this needs to be a setting
		});
		// TODO: check to see if the note has already been published
		const url = `${baseUrl}/posts.json`;

		const response = await fetch(url, { method: "POST", headers, body });

		if (!response.ok) {
			console.error("Error publishing to Discourse:", response.status);
			return { message: "Error publishing to Discourse" };
		}
        
		const jsonResponse = await response.json();
		// TODO: use the response to add a discoursePostId file property
		console.log(`jsonResponse: ${JSON.stringify(jsonResponse, null, 2)}`);
		return { message: "success" };
	} catch (error) {
		console.error("Error publishing to Discourse:", error);
		return { message: `Error: ${error.message}` };
	}
}

من الممكن أن يكون هناك حل بديهي أغفله. إذا لم يكن الأمر كذلك، فهل هناك أي طريقة يمكن لـ Discourse السماح بذلك؟ تبدو إضافة Obsidian Discourse مفيدة. (التنفيذ الصحيح سيكون أكثر تعقيدًا مما نشرته أعلاه.)

3 إعجابات

كنت مرتبكًا في البداية، لكنني أفهم الآن، لقد قمت بتكوين تطبيق Obsidian الخاص بك بمفتاحك ولا يمكن لأحد الوصول إليه سواك. هذا لا يحدث في متصفح، لذا لا يمتلك الأشخاص على الإنترنت مفتاحك.

لدي إضافة Discourse تعالج نماذج عشوائية (يمكنك استخدامها على https://www.formhoster.com/). أردت أن أجعلها قادرة على العمل كمستخدم حالي إذا كان المستخدم قد سجل الدخول إلى الموقع الذي يعالج النموذج، وواجهت ما أعتقد أنه نفس مشكلة CORS واستسلمت بسرعة كبيرة. كان جهازي في متصفح بدلاً من تطبيق مثل Obsidian، لكنني أعتقد أن المشكلة قد تكون متشابهة.

كل ذلك لأقول إنني أعتقد أنه ليس لدي أي أفكار جيدة، لكنني آمل أن يكون لدى شخص آخر. :person_shrugging:

إعجاب واحد (1)

صحيح، Obsidian هو تطبيق Electron يعمل محليًا. يستخدم التخزين المحلي، لذا يبقى مفتاح API على جهاز المستخدم.

اتضح أن هناك حلاً لمشكلة CORS. لقد اختبرته فقط على جهاز الكمبيوتر المكتبي الخاص بي حتى الآن. أيضًا، Discourse رائع!

كان الكود الذي نشرته أعلاه بحاجة إلى تعديل ليصبح:

import DiscoursePlugin from "./main";
import { requestUrl, TFile } from "obsidian";

//...

		const response = await requestUrl({
			url: url,
			method: "POST",
			contentType: "application/json",
			body,
			headers,
		});
//...

السؤال التالي سيكون حول السماح للمستخدمين بطلب مفاتيح API للمستخدم من التطبيق، ولكن هذه مسألة منفصلة.

3 إعجابات

هل هذا مكون إضافي تعمل عليه؟ لدي مستخدم (وأنا نفسي) يرغب بشدة في استخدام هذا. يمكنني محاولة إعادة إنشاء ما قمت به، ولكن إذا كانت هناك طريقة أسهل…

كانت بداية لشيء ما. لأغراضي الخاصة، أنا مهتم أكثر بتطبيق سطر الأوامر (CLI) الذي يسمح بمزامنة خزنة Obsidian مع منتدى Discourse. يسهل تطبيق سطر الأوامر التعامل مع مزامنة خزنة كاملة أو دليل فرعي، والتعامل مع الروابط الداخلية في الملاحظات، والتعامل مع التحميلات، وما إلى ذلك. يتناسب نهج تطبيق سطر الأوامر أيضًا مع بعض الأعمال الأخرى التي أقوم بها، لذلك أتعلم شيئًا مفيدًا منه.

العيب الكبير لتطبيق سطر الأوامر هو أنه يتطلب من أي شخص يستخدمه تثبيت Ruby على جهازه. سيعمل أيضًا فقط على أجهزة الكمبيوتر المكتبية. ستكون هناك بعض التحديات التقنية مع استخدامه على أجهزة الكمبيوتر التي تعمل بنظام Windows.

سأنشر رابطًا للتطبيق هنا بمجرد أن يكون جاهزًا للمشاركة.

إذا كان مكون Obsidian Discourse الإضافي، بدلاً من تطبيق سطر الأوامر، شيئًا يهتم به الناس، فسألقي نظرة عليه مرة أخرى في المستقبل. من الممكن أن يصل شخص آخر إلى ذلك قبلي. لم أتقدم به كثيرًا بعد مثال الكود المنشور أعلاه.

إعجاب واحد (1)

إذا كان هذا كل ما لديك حتى الآن، فيبدو بسيطًا جدًا. أتساءل كيف سيتعامل مع الصور في هذه المرحلة. سأكون على استعداد لمحاولة ذلك. لم أكتب إضافة لـ Obsidian من قبل، ولكن من خلال ما اطلعت عليه (نظرات عابرة على إضافات أخرى)، لا يبدو الأمر معقدًا للغاية.

إعجاب واحد (1)

هذا هو المكان المناسب للبدء: Build a plugin - Developer Documentation. كنت سأضع رابطًا لما فعلته، ولكنه أحد المشاريع القليلة (نأمل أن يكون الوحيد) التي لم أقم بدفعها إلى Github قبل إعادة تثبيت نظام التشغيل على جهاز الكمبيوتري الأسبوع الماضي.

سيتعين عليك معرفة كيفية القيام بذلك باستخدام Node. يوجد مثال جيد بلغة Ruby هنا: discourse_api/examples/upload_file.rb at main · discourse/discourse_api · GitHub. يستدعي: discourse_api/lib/discourse_api/api/uploads.rb at main · discourse/discourse_api · GitHub.

هل يمكنك مشاركة هذا الجزء؟

حسنًا، كان فقدان هذا الرمز متهورًا إلى حد ما. على ما أذكر، كنت أقوم باستيراد DiscoursePlugin المعرفة في main.ts إلى ملف كان يتعامل مع استدعاء لـ this.addCommand. للبدء، يمكنك القيام بكل شيء في main.ts. سأتبع الدليل للبدء بالملحق المثال. ابدأ بالعبث به ومحاولة جعل شيئًا ما يحدث. أعرف أنني استخدمت هذا الملحق كقالب لملحقي.

هناك بعض الأمثلة الجيدة هنا أيضًا: obsidian-wordpress/src at main · devbean/obsidian-wordpress · GitHub.

إعجاب واحد (1)

حسنًا، سأضع علامة على هذا في الوقت الحالي. لقد أحرزت تقدمًا جيدًا، ولكن هناك بعض الأشياء التي لا تعجبني.

  • مفتاح API مخزن كنص عادي (سيء جدًا)
  • الصور لا يتم تحميلها، هناك بعض إعدادات التكوين التي لم أستكشفها بعد. لكنني لست من محبي إعداد حاوية AWS S3. سأبحث في ذلك لاحقًا.
  • بعض الخيارات الأسلوبية يمكن أن تكون أفضل، لكنني أردت شيئًا وظيفيًا
  • يجب تحديث ملف README. ولكن مرة أخرى، أردت فقط شيئًا وظيفيًا ومنشورًا.
إعجاب واحد (1)

أتساءل عما إذا كانت هناك طريقة لتجاوز ذلك. في تطبيق سطر الأوامر، أقوم بتشفيره بكلمة مرور. يجب على المستخدم تقديم كلمة المرور قبل أي عملية تستخدم مفتاح واجهة برمجة التطبيقات.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.