التعلم العميق والأمن العملي القائم على الويب بالقدوة

Daisyصورة الملف الشخصي

بواسطة Daisy

التعلم العميق والأمان القائم على الويب القائم على الويب على سبيل المثال الطبعة الثالثة شارلوت هاربر 3 يوليو 2024 مقدمة: تعد اعتبارات الأمان في إنشاء البرامج للويب جزءًا مهمًا من خطة أي مطور على الويب وتنفيذها مع هندسة نموذج أولي يمكن الاعتماد عليه ومستقر ومفيد للأغراض العملية. تمييز DOM (علامة كائن الوثيقة) ، مع تنفيذ HTML و JavaScript و CSS بالإضافة إلى برامج الخلفية التي تنفذ Python و C/C ++ و Java و Bash ، تمنح مطوري الويب الحرية والقوة لإنشاء مجموعة واسعة من المشاريع التي تعبر عنها الإبداع ، وتوفير سهولة الاستخدام والوظائف ، وتصوير التواضع والشخصية ، وتوفير سهولة الاستخدام بالإضافة اقتل الوقت أو قم بإنجاز شيء ما على الإنترنت ، وعادةً ما يكون على جهاز الهاتف الذكي الشاشة. معظم الناس لا يعرفون من أين يبدأون عندما يرغبون في إنشاء موقع ويب من الصفر ،يميلون إلى البدء على موقع الويب الخاص بشخص آخر وبناء شيء محدود في الوظيفة ، والاعتمادية ، وسهولة الاستخدام ، وخاصة الإبداع عندما كان من الممكن أن يكون لديهم أحدث الأدوات القوية تحت تصرفه من أجل بناء شيء مفيد دون إضاعة الأزرار الزمنية ، و لا سيما إهدار الأموال التي تدفع مقابل الاشتراكات باهظة الثمن للبرمجيات التي أراد قلة من الناس استخدامها على أي حال بالنظر إلى قيودها في سهولة الاستخدام والمرونة. إذا كان لديك بضع دقائق لقراءة هذا الكتاب ومعرفة ما أريد أن تعلمك ، أو حتى التحدث معي شخصياً عن أهدافك والحصول على بعض التوجيهات في الاتجاه الصحيح ، ودافعًا عن تعلم الكود وكتابة البرامج الخاصة بك ، خذ هذا الكتاب إلى المنزل وقم بتجريد بعض الوقت لتعلم بناء تطبيق الويب المؤثر والقوي والبسيط والهمين ، وهو موقع ويب يتواجد كل شيء عليك ويفعل بالضبط ما تريده ويلبي احتياجات جمهورك. ْعَنِّي: أنا مطور برامج بعرضAnge of Experience in C/C ++ و Java و Python و HTML و CSS و JavaScript. أقوم ببناء مواقع الويب التي يرغب الناس في استخدامها ، وأرغب في زيارتها ، وحتى الحصول على مدمن لاستخدامها لمجرد التعلم وإعادة إنشاء وقت القتل ، والأهم من ذلك ، أبيع البرامج. إذا كان لديك فكرة عن كيفية رغبتك في الحصول على موقع ويب للبحث عن موقع ويب ، كنت على استعداد لدعمي حتى أتمكن من تلبية احتياجاتي الخاصة أثناء قابلك ، وأنت على استعداد لتغطية تكاليف تشغيل موقع ويب بنفسك ، أود أن أنشأك على YouTube أو Tiktok أو Twitter أو Google أو حتى تطبيق أمان عالي التقنية يمكنك الوصول إليه فقط. بدلاً من محاولة بيعك وقتي ، أحاول شراء لك: أريد أن أتحدث معك في إنشاء تطبيق (موقع ويب) بنفسك بالمعلومات الموجودة بالفعل ، وأعلمك ما تحتاجه لتكون مطور برامج مستقل ، رجل أعمال ، يقود مهنة ناجحة في أي مجال تريده. واسمحوا لي أن أكون واضحا ، فإن التعليم الذي أعطيك سيكون غير رسمي. يمكنك الذهاب إلى المدرسة وتعلم كل هذا مع أRMAL Education ، أو حتى قراءة هذا الكتاب في المدرسة ، أكمل مهامك ، وأخذ الكثير من تعليمك ، لكنني لن أضعك رسميًا في المقعد الساخن وأطلب منك إكمال المهام. أنا لست أستاذي ، يمكنك أن تفكر بي كصديق يريد إرشادك نحو مهنة يقودها نجاحك الشخصي. وأنا لا أبيع لك النجاح أيضًا ، ستحتاج إلى شرائه مع وقتك. إن تعلم الكود له منحنى تعليمي حاد ولم يكن سهلاً أبدًا ، أو حتى من المفترض أن يكون كذلك. تحتاج إلى العمل بجد قدر الإمكان والاستمرار في المحاولة والفشل والمحاولة مرة أخرى حتى عندما تشعر بالإحباط من أجل التعلم وبناء التطبيقات بنفسك. هذا في طبيعة الكود نفسه. يتم تشغيل الكود بواسطة برنامج التحويل البرمجي المصمم لإعطاء رسائل خطأ المبرمج ، وسيعلمك ذلك كيفية الترميز ، حتى لو كنت ببساطة تقوم بنسخ الخطأ إلى محرك البحث الخاص بك وقراءة أمثلة الآخرين. ويجب أن أقول ، لا تحتاج إلى أن تكون غنيًا للغاية ، ذكيًا ، ناجحًا ،EN التفاصيل موجهة أو منظمة لإنشاء تطبيق. الكمبيوتر يهتم بهذه المنظمة نيابة عنك. تحتاج فقط إلى المثابرة من خلال التجربة والخطأ ، والحفاظ على التركيز والعمل بجد على ما تفعله ، وسيكون لديك مهنة ناجحة للغاية في مجمل ما تفعله. من أكون: أدرك أن القسم الأخير كان أكثر عن التعلم واتخاذ طرق من هذا الكتاب. من أنا بالضبط؟ هذا سؤال معقد. أنا غير واضح في ذلك بنفسي ، لأنني أعاني من الحالات الطبية التي يمكن أن تجعل من الصعب علي حتى أن رمز أو أكتب هذا الكتاب في بعض الأحيان ، مع تقديم التحديات مع القضايا الاجتماعية والهوية التي تجعل حياتي أكثر صعوبة عندما يتعلق الأمر بتقديم نفسي . باختصار ، إذا كنت تقرأ هذا الكتاب ، فقد أحضرته إلى المنزل لأنك انقلبت واعتقدت أنه كان مفيدًا ، أو حتى إذا كنت قد قرأت هذا بعيدًا ، فأنا فرد مشابه يريد أن يراك تنجح كل ما تفعله. أنا مهندس نفسي ، برنامجالمطور ، وطالب ، وأنا أكتب هذا الكتاب للطلاب الآخرين الذين يرغبون في جعل حياتهم أسهل من خلال امتلاك كتيب للبرنامج الذي يحتاجونه إلى جعل حياتهم أسهل من خلال إعطاء أمثلة لنسخها التي تتناسب معًا مثل لغز كبير في العمل ، تطبيق مفيد ، كبير ، وظيفي ، متماسك ، وجذاب يمكن أن يدفع النجاح بغض النظر عن خط العمل. إلى حد كبير ، هذا ما أقوم به: أقوم ببناء تطبيقات لمساعدة نفسي والآخرين على النجاح. أنا مؤلف أيضًا ، على الرغم من أن هذا هو أول منشور لي أعتزم إكماله من أجل وضع محفظتي معًا في وثيقة مفيدة ، وأنا فنان أيضًا. سأعترف بذلك لك ، أنا شخص غريب نوعًا ما. أنا لست مثاليًا ، لقد قمت بتشغيل INS مع القانون حتى يقودني إلى ترك الكليات والجامعات وترك الولايات من أجل محاولة صنع اسم لنفسي بمزيد من النجاح. أنا امرأة بالولادة ، أرتدي مكياجًا ، وألتقط صورًا لنفسي ، وأرتدي الفساتين وغيرها من الملابس النسائية ، وأظل على وعي بنفسي كذكر بطبيعته. لقد واجهت مشكلات مع أشخاص آخرين في الماضي تؤدي إلى صراعات من خلال الكتابة وبناء WebApps ، وأعتذر أنني لم أتمكن من الحصول على هذا الكتاب في يديك عاجلاً: كنت بحاجة إلى هذا. سترغب في قراءة الكود وكتابته يشبهني ويعمل مثل لي ويفعل نفس الشيء ولكنه أفضل ، لأنه إذا كنت تستطيع شراء هذا الكتاب بدلاً من أن يسلح لوحة المفاتيح الخاصة بك مثلما أفعل فقط لإنشاء كتاب بنفسك عن المال لذلك ، لديك الموارد التي تحتاجها لتكون ناجحة في حياتك. كان لدي كل أنواع القضايا مع العائلة التي تكبر ، والظروف الصحية ، والأطباء ، ووسائل الإعلام ، والقانون ، ويعكس قانوني العميق الصراع الذي هو النسوية والطبيعة الإناث في عالم منقسم ومحبط. ومع ذلك ، فإن هذا الكتاب هو شيء يهمني بشدة ، طفلي ، محفظتي ، وسبل عيشتي ، لذلك أقدر اعتبارك عندما تأخذ النص إلى المنزل وتتأمل بعناية من أجل التعلم مني. من فضلك ضع في اعتبارك أنني لست مثاليًا ،سيكون للكتاب أخطاء ومراجعات وإصدارات جديدة ، وستحتاج إلى التفكير في عقلك المنطقي قدر الإمكان من أجل الحصول على تجربة ناجحة في كتاباتي. أيضًا ، افهم أنني أقصد جيدًا لك حتى عندما تواجه التحديات عند الكتابة. فكر في الأمر على هذا النحو: عندما يمكنك فقط استئجار نظام كمبيوتر لفعل أي شيء يمكن أن تتخيله في المساحة الرقمية ، وتخزين جميع المعلومات التي تواجهها ، و #$ ٪! yze وتنظيمها ، والتفهمها ، ستفعل ذلك يواجه حتما صعوبات في المعلومات التي تتناولها وحتى النشر. أقول لك هذا لأنني واجهت نفس الصعوبات. استخدم هذا الكتاب على مسؤوليتك الخاصة ، والعمل مع مجتمعك ومجتمعاتك المتاحة لك لإنشاء البرامج ضمن إعداد آمن ، ولا تأخذ الأشياء إلى شخصياً عندما تفشل أو حتى تنجح بالطريقة الخطأ: هكذا حصلت على هذا الوقت ولماذا يمكنني أن أحضر لك هذا النص ومساعدتك على النجاح دون التباعد على طريق الجنون الذي يغادرلقد دمرت ، ممزقة ومتوترة أثناء مواجهة المشكلات العادية التي يواجهها الجميع على نطاق عالمي بفضل النطاق العالمي الباغيمي للشبكة التي سنعمل عليها ، الإنترنت. قد لا تكون على دراية بمن أنا فقط ببضع كلمات ، لكنني أشجعك على القراءة ، وسوف تعرفني وأنت تواصل القراءة وفهمي أثناء بناء مشاريعك الخاصة لإكمال عملك. لن يكون هناك أي واجب منزلي مع هذا الكتاب ، طالما أن أساتذتك أو المعلمين لا يعينونك ، لكنني أشجعك بشدة على بناء مجموعة من المشاريع بنفسك أثناء قراءتك ، بالإضافة إلى مشروع Capstone الذي يعرض كيف يمكنك تطبيق ما تعلمته. يعد مشروع Capstone الخاص بي هو الأساس لمعظم ما ستقرأه في هذا الكتاب ، حيث أنه يدمج رمزًا من مشاريعي السابقة ، والرمز الذي قمت بإنشائه وتعلمت الكتابة بشكل منهجي ، ومجموعة واسعة من الأفكار والنصائح التي ساعدتني تنجح إلى النقطة التي يمكنني فيها تدوير تطبيق بسيطظهرت وتبدو وتصرف مثل تطبيق شهير قد ترى صديقك أو عائلتك يستخدم ، على الإنترنت ، المعلن عنه ، أو في الأخبار. ما هو هذا الكتاب: هذا الكتاب هو برنامج تعليمي بالقدوة. يمكنك العثور على رمز هنا ، وإرشادات حول كيفية تعلم التعليمات البرمجية ، ومعلومات عن رمز تصحيح الأخطاء ، وإصلاح الأخطاء ، واستكشاف الأخطاء وإصلاحها ، والتعليمات حول كيفية النسخ الاحتياطي وحفظ الكود الخاص بك ، وإعادة النشر إذا قام أي شخص بتقسيم الرمز الخاص بك ، وتأمين الرمز ، ونشره الكود الخاص بك ، وإنشاء مواقع الويب التفاعلية التي تسلية ، وجذابة ، وإدمان ، وستحصل على شعور بمن أنا ، ولماذا هذا مهم ، وكيفية تصوير نفسك وتطبيقك وصورة شركتك ، وكذلك البرامج التي تبنيها في أفضل ضوء مطلق لتكون الأكثر جاذبية قدر الإمكان للمستخدمين النهائيين ، زوار موقع الويب الخاص بك. في هذا الكتاب ، سأعرض عددًا من أمثلة تصميم البرامج مع التركيز على الويب كمنصة وكذلك الأمان. سنبدأ تجربة التعلم من خلال بناء أساسيإلخ باستخدام قذيفة UNIX ، مع ميزات النسخ الاحتياطي والبرمجة. بعد ذلك ، سنقوم بفحص موقع مدونة أساسي ، وترقية مدونتنا بميزات الصور والفيديو بالإضافة إلى استخدام هذه الميزات لتوظيف حلول الأمان باستخدام برنامج مجاني ، وتأمين خادمنا باستخدام وحدة مصادقة قابلة للتوصيل (PAM). سنقوم بعد ذلك بمراجعة معالجة الملفات ومعالجتها واستكشاف تحرير الفيديو والتبرع الصوتي ومسح الباركود والتعرف على الأحرف البصرية ، من بين مفاهيم أخرى. على طول الطريق ، سنقوم بفحص واجهات برمجة التطبيقات التي ستساعدنا على جعل برنامجنا أكثر فائدة وأمانًا ، مع خيارات مجانية ومدفوعة. على طول الطريق ، سوف نستكشف الأمن المادي والأدوات المسلحة مثل تصميم الأسلحة النارية والذخائر وتصنيعها بما في ذلك تصميم البراميل والكرات ، وتصميم البرج والطائرات بدون طيار ، وغيرهم من المديرين الذين سندمجه مع برنامجنا على الشبكة الحالية من أجل حماية برامجنا وإظهار الدفاع عن النفس والتواطؤ. سنأخذ فترات راحة على طول الطريق لبناء الألعاب ، ثنائية الأبعاد و 3Dمحركات ndering ، والعمل مع الأجهزة المدمجة في حالة دراسة أمثلة على دراسة برامج تقديم الأبعاد الأساسية ومدلك الاهتزاز الإلكتروني يلقي في مطاط السيليكون على التوالي. على طول الطريق ، سنستخدم أيضًا حلول التعلم الآلي المتاحة بالفعل من أجل تأمين برنامجنا بشكل أفضل. سنستخدم أيضًا أدوات الأسهم المتاحة للويب من أجل تبسيط العملية وتأمينها. هذا الكتاب هو دليل لنجاحك في بناء تطبيق ويب ودمجه مع شبكة مهنية من الكمبيوتر والأنظمة الميكانيكية المدمجة ، وإجمالي دليل بناء البرامج والأجهزة المضمنة دون معرفة أساسية أو خبرة سابقة. ما ليس هذا الكتاب: إذا كنت ترغب حقًا في الحصول على موقع ويب ، فيمكنك فقط إعداد متجر بسيط وبيع ما تحتاجه ، أو نشر مدونة ، أو نشر صور أو مقاطع فيديو ، أو غير ذلك دون كتابة سطر واحد من التعليمات البرمجية. هذا الكتاب ليس ذلك. سوف يعلمك هذا الكتاب كيفية إنشاء برنامج أكثر فائدة وكاملةقد يكون من المفيد تشغيله على نطاق واسع من أي برنامج يمكنك العثور عليه بالفعل ، لأنه ينشر أحدث البرامج التي لا تزال نماذج أولية ، قد تكون مكلفة على نطاق واسع ، ولا تروق للشركات المعقدة. كسب المال للأشخاص الذين لا يفعلو...
التعلم العميق والأمن العملي القائم على الويب بالقدوة

التعلم العميق والأمان القائم على الويب القائم على الويب على سبيل المثال الطبعة الثالثة شارلوت هاربر 3 يوليو 2024 مقدمة: تعد اعتبارات الأمان في إنشاء البرامج للويب جزءًا مهمًا من خطة أي مطور على الويب وتنفيذها مع هندسة نموذج أولي يمكن الاعتماد عليه ومستقر ومفيد للأغراض العملية. تمييز DOM (علامة كائن الوثيقة) ، مع تنفيذ HTML و JavaScript و CSS بالإضافة إلى برامج الخلفية التي تنفذ Python و C/C ++ و Java و Bash ، تمنح مطوري الويب الحرية والقوة لإنشاء مجموعة واسعة من المشاريع التي تعبر عنها الإبداع ، وتوفير سهولة الاستخدام والوظائف ، وتصوير التواضع والشخصية ، وتوفير سهولة الاستخدام بالإضافة اقتل الوقت أو قم بإنجاز شيء ما على الإنترنت ، وعادةً ما يكون على جهاز الهاتف الذكي الشاشة. معظم الناس لا يعرفون من أين يبدأون عندما يرغبون في إنشاء موقع ويب منخدش ، سوف يميلون إلى البدء على موقع الويب الخاص بشخص آخر وبناء شيء محدود في الوظيفة ، والاعتمادية ، وسهولة الاستخدام ، وخاصة الإبداع عندما كان يمكن أن يكون لديهم أحدث الأدوات القوية تحت تصرفه من أجل بناء شيء مفيد دون إضاعة الأزرار الزمنية ، وخاصة إهدار الأموال التي تدفع مقابل الاشتراكات باهظة الثمن للبرامج التي أراد قلة من الناس استخدامها على أي حال نظرًا لقيودها في سهولة الاستخدام والمرونة. إذا كان لديك بضع دقائق لقراءة هذا الكتاب ومعرفة ما أريد أن تعلمك ، أو حتى التحدث معي شخصياً عن أهدافك والحصول على بعض التوجيهات في الاتجاه الصحيح ، ودافعًا عن تعلم الكود وكتابة البرامج الخاصة بك ، خذ هذا الكتاب إلى المنزل وقم بتجريد بعض الوقت لتعلم بناء تطبيق الويب المؤثر والقوي والبسيط والهمين ، وهو موقع ويب يتواجد كل شيء عليك ويفعل بالضبط ما تريده ويلبي احتياجات جمهورك. ْعَنِّي: أنا مطور برامج معمجموعة من الخبرة في C/C ++ ، Java ، Python ، HTML ، CSS و JavaScript. أقوم ببناء مواقع الويب التي يرغب الناس في استخدامها ، وأرغب في زيارتها ، وحتى الحصول على مدمن لاستخدامها لمجرد التعلم وإعادة إنشاء وقت القتل ، والأهم من ذلك ، أبيع البرامج. إذا كان لديك فكرة عن كيفية رغبتك في الحصول على موقع ويب للبحث عن موقع ويب ، كنت على استعداد لدعمي حتى أتمكن من تلبية احتياجاتي الخاصة أثناء قابلك ، وأنت على استعداد لتغطية تكاليف تشغيل موقع ويب بنفسك ، أود أن أنشأك على YouTube أو Tiktok أو Twitter أو Google أو حتى تطبيق أمان عالي التقنية يمكنك الوصول إليه فقط. بدلاً من محاولة بيعك وقتي ، أحاول شراء لك: أريد أن أتحدث معك في إنشاء تطبيق (موقع ويب) بنفسك بالمعلومات الموجودة بالفعل ، وأعلمك ما تحتاجه لتكون مطور برامج مستقل ، رجل أعمال ، يقود مهنة ناجحة في أي مجال تريده. واسمحوا لي أن أكون واضحا ، فإن التعليم الذي أعطيك سيكون غير رسمي. يمكنك الذهاب إلى المدرسة وتعلم كل هذا مع أالتعليم الرسمي ، أو حتى قراءة هذا الكتاب في المدرسة ، أكمل مهامك ، وأخذ الكثير من تعليمك ، لكنني لن أضعك رسميًا في المقعد الساخن وأطلب منك إكمال المهام. أنا لست أستاذي ، يمكنك أن تفكر بي كصديق يريد إرشادك نحو مهنة يقودها نجاحك الشخصي. وأنا لا أبيع لك النجاح أيضًا ، ستحتاج إلى شرائه مع وقتك. إن تعلم الكود له منحنى تعليمي حاد ولم يكن سهلاً أبدًا ، أو حتى من المفترض أن يكون كذلك. تحتاج إلى العمل بجد قدر الإمكان والاستمرار في المحاولة والفشل والمحاولة مرة أخرى حتى عندما تشعر بالإحباط من أجل التعلم وبناء التطبيقات بنفسك. هذا في طبيعة الكود نفسه. يتم تشغيل الكود بواسطة برنامج التحويل البرمجي المصمم لإعطاء رسائل خطأ المبرمج ، وسيعلمك ذلك كيفية الترميز ، حتى لو كنت ببساطة تقوم بنسخ الخطأ إلى محرك البحث الخاص بك وقراءة أمثلة الآخرين. ويجب أن أقول ، لا تحتاج إلى أن تكون غنيًا للغاية ، ذكيًا ،Esful ، أو حتى التفاصيل موجهة أو منظمة لإنشاء تطبيق. الكمبيوتر يهتم بهذه المنظمة نيابة عنك. تحتاج فقط إلى المثابرة من خلال التجربة والخطأ ، والحفاظ على التركيز والعمل بجد على ما تفعله ، وسيكون لديك مهنة ناجحة للغاية في مجمل ما تفعله. من أكون: أدرك أن القسم الأخير كان أكثر عن التعلم واتخاذ طرق من هذا الكتاب. من أنا بالضبط؟ هذا سؤال معقد. أنا غير واضح في ذلك بنفسي ، لأنني أعاني من الحالات الطبية التي يمكن أن تجعل من الصعب علي حتى أن رمز أو أكتب هذا الكتاب في بعض الأحيان ، مع تقديم التحديات مع القضايا الاجتماعية والهوية التي تجعل حياتي أكثر صعوبة عندما يتعلق الأمر بتقديم نفسي . باختصار ، إذا كنت تقرأ هذا الكتاب ، فقد أحضرته إلى المنزل لأنك انقلبت واعتقدت أنه كان مفيدًا ، أو حتى إذا كنت قد قرأت هذا بعيدًا ، فأنا فرد مشابه يريد أن يراك تنجح كل ما تفعله. أنا مهندس بنفسيالمطور ، وطالب ، وأنا أكتب هذا الكتاب للطلاب الآخرين الذين يرغبون في جعل حياتهم أسهل من خلال امتلاك كتيب للبرنامج الذي يحتاجونه إلى جعل حياتهم أسهل من خلال إعطاء أمثلة لنسخها التي تتناسب معًا مثل لغز كبير في العمل ، تطبيق مفيد ، كبير ، وظيفي ، متماسك ، وجذاب يمكن أن يدفع النجاح بغض النظر عن خط العمل. إلى حد كبير ، هذا ما أقوم به: أقوم ببناء تطبيقات لمساعدة نفسي والآخرين على النجاح. أنا مؤلف أيضًا ، على الرغم من أن هذا هو أول منشور لي أعتزم إكماله من أجل وضع محفظتي معًا في وثيقة مفيدة ، وأنا فنان أيضًا. سأعترف بذلك لك ، أنا شخص غريب نوعًا ما. أنا لست مثاليًا ، لقد قمت بتشغيل INS مع القانون حتى يقودني إلى ترك الكليات والجامعات وترك الولايات من أجل محاولة صنع اسم لنفسي بمزيد من النجاح. أنا امرأة بالولادة ، أرتدي مكياجًا ، وألتقط صورًا لنفسي ، وأرتدي الفساتين وغيرها من الملابس النسائية ، وأظل على وعي بنفسي كأنثى بطبيعتها. لقد واجهت مشكلات مع أشخاص آخرين في الماضي تؤدي إلى صراعات من خلال الكتابة وبناء WebApps ، وأعتذر أنني لم أتمكن من الحصول على هذا الكتاب في يديك عاجلاً: كنت بحاجة إلى هذا. سترغب في قراءة الكود وكتابته يشبهني ويعمل مثل لي ويفعل نفس الشيء ولكنه أفضل ، لأنه إذا كنت تستطيع شراء هذا الكتاب بدلاً من أن يسلح لوحة المفاتيح الخاصة بك مثلما أفعل فقط لإنشاء كتاب بنفسك عن المال لذلك ، لديك الموارد التي تحتاجها لتكون ناجحة في حياتك. كان لدي كل أنواع القضايا مع العائلة التي تكبر ، والظروف الصحية ، والأطباء ، ووسائل الإعلام ، والقانون ، ويعكس قانوني العميق الصراع الذي هو النسوية والطبيعة الإناث في عالم منقسم ومحبط. ومع ذلك ، فإن هذا الكتاب هو شيء يهمني بشدة ، طفلي ، محفظتي ، وسبل عيشتي ، لذلك أقدر اعتبارك عندما تأخذ النص إلى المنزل وتتأمل بعناية من أجل التعلم مني. من فضلك ضع في اعتبارك أنني لستECT ، سيكون لهذا الكتاب أخطاء ومراجعات وإصدارات جديدة ، وستحتاج إلى التفكير في عقلك المنطقي قدر الإمكان من أجل الحصول على تجربة ناجحة في كتابتي. أيضًا ، افهم أنني أقصد جيدًا لك حتى عندما تواجه التحديات عند الكتابة. فكر في الأمر على هذا النحو: عندما يمكنك فقط استئجار نظام كمبيوتر لفعل أي شيء يمكن أن تتخيله في المساحة الرقمية ، وتخزين جميع المعلومات التي تواجهها ، و #$ ٪! yze وتنظيمها ، والتفهمها ، ستفعل ذلك يواجه حتما صعوبات في المعلومات التي تتناولها وحتى النشر. أقول لك هذا لأنني واجهت نفس الصعوبات. استخدم هذا الكتاب على مسؤوليتك الخاصة ، والعمل مع مجتمعك ومجتمعاتك المتاحة لك لإنشاء البرامج ضمن إعداد آمن ، ولا تأخذ الأشياء إلى شخصياً عندما تفشل أو حتى تنجح بالطريقة الخطأ: هكذا حصلت على هذا الوقت ولماذا يمكنني أن أحضر لك هذا النص ومساعدتك على النجاح دون التباعد على طريق الجنوندمرني Aves Me ، ممزقة ومتوترة أثناء مواجهة المشكلات العادية التي يواجهها الجميع على نطاق عالمي بفضل النطاق العالمي البادلي للشبكة التي سنعمل عليها ، الإنترنت. قد لا تكون على دراية بمن أنا فقط ببضع كلمات ، لكنني أشجعك على القراءة ، وسوف تعرفني وأنت تواصل القراءة وفهمي أثناء بناء مشاريعك الخاصة لإكمال عملك. لن يكون هناك أي واجب منزلي مع هذا الكتاب ، طالما أن أساتذتك أو المعلمين لا يعينونك ، لكنني أشجعك بشدة على بناء مجموعة من المشاريع بنفسك أثناء قراءتك ، بالإضافة إلى مشروع Capstone الذي يعرض كيف يمكنك تطبيق ما تعلمته. يعد مشروع Capstone الخاص بي هو الأساس لمعظم ما ستقرأه في هذا الكتاب ، حيث أنه يدمج رمزًا من مشاريعي السابقة ، والرمز الذي قمت بإنشائه وتعلمت الكتابة بشكل منهجي ، ومجموعة واسعة من الأفكار والنصائح التي ساعدتني تنجح إلى النقطة التي يمكنني فيها تدوير تطبيق بسيطمميز بالكامل وتبدو ويتصرف مثل التطبيق الشهير الذي قد ترى صديقك أو عائلتك يستخدم ، على الإنترنت ، المعلن عنه لك ، أو في الأخبار. ما هو هذا الكتاب: هذا الكتاب هو برنامج تعليمي بالقدوة. يمكنك العثور على رمز هنا ، وإرشادات حول كيفية تعلم التعليمات البرمجية ، ومعلومات عن رمز تصحيح الأخطاء ، وإصلاح الأخطاء ، واستكشاف الأخطاء وإصلاحها ، والتعليمات حول كيفية النسخ الاحتياطي وحفظ الكود الخاص بك ، وإعادة النشر إذا قام أي شخص بتقسيم الرمز الخاص بك ، وتأمين الرمز ، ونشره الكود الخاص بك ، وإنشاء مواقع الويب التفاعلية التي تسلية ، وجذابة ، وإدمان ، وستحصل على شعور بمن أنا ، ولماذا هذا مهم ، وكيفية تصوير نفسك وتطبيقك وصورة شركتك ، وكذلك البرامج التي تبنيها في أفضل ضوء مطلق لتكون الأكثر جاذبية قدر الإمكان للمستخدمين النهائيين ، زوار موقع الويب الخاص بك. في هذا الكتاب ، سأعرض عددًا من أمثلة تصميم البرامج مع التركيز على الويب كمنصة وكذلك الأمان. سنبدأ تجربة التعلم من خلال بناء أساسيOJECT باستخدام قذيفة UNIX ، مع ميزات النسخ الاحتياطي والبرمجة. بعد ذلك ، سنقوم بفحص موقع مدونة أساسي ، وترقية مدونتنا بميزات الصور والفيديو بالإضافة إلى استخدام هذه الميزات لتوظيف حلول الأمان باستخدام برنامج مجاني ، وتأمين خادمنا باستخدام وحدة مصادقة قابلة للتوصيل (PAM). سنقوم بعد ذلك بمراجعة معالجة الملفات ومعالجتها واستكشاف تحرير الفيديو والتبرع الصوتي ومسح الباركود والتعرف على الأحرف البصرية ، من بين مفاهيم أخرى. على طول الطريق ، سنقوم بفحص واجهات برمجة التطبيقات التي ستساعدنا على جعل برنامجنا أكثر فائدة وأمانًا ، مع خيارات مجانية ومدفوعة. على طول الطريق ، سوف نستكشف الأمن المادي والأدوات المسلحة مثل تصميم الأسلحة النارية والذخائر وتصنيعها بما في ذلك تصميم البراميل والكرات ، وتصميم البرج والطائرات بدون طيار ، وغيرهم من المديرين الذين سندمجه مع برنامجنا على الشبكة الحالية من أجل حماية برامجنا وإظهار الدفاع عن النفس والتواطؤ. سنأخذ فترات راحة على طول الطريق لبناء الألعاب ، ثنائية الأبعاد و 3Dالمحركات النهائية ، والعمل مع الأجهزة المدمجة في حالة دراسة أمثلة على دراسة برامج تقديم الأبعاد الأساسية ومدلك تهتز إلكتروني يلقي في مطاط السيليكون على التوالي. على طول الطريق ، سنستخدم أيضًا حلول التعلم الآلي المتاحة بالفعل من أجل تأمين برنامجنا بشكل أفضل. سنستخدم أيضًا أدوات الأسهم المتاحة للويب من أجل تبسيط العملية وتأمينها. هذا الكتاب هو دليل لنجاحك في بناء تطبيق ويب ودمجه مع شبكة مهنية من الكمبيوتر والأنظمة الميكانيكية المدمجة ، وإجمالي دليل بناء البرامج والأجهزة المضمنة دون معرفة أساسية أو خبرة سابقة. ما ليس هذا الكتاب: إذا كنت ترغب حقًا في الحصول على موقع ويب ، فيمكنك فقط إعداد متجر بسيط وبيع ما تحتاجه ، أو نشر مدونة ، أو نشر صور أو مقاطع فيديو ، أو غير ذلك دون كتابة سطر واحد من التعليمات البرمجية. هذا الكتاب ليس ذلك. سوف يعلمك هذا الكتاب كيفية إنشاء برنامج أكثر فائدة وكاملةقد يكون من المفيد تشغيله على نطاق واسع من أي برنامج يمكنك العثور عليه بالفعل ، لأنه ينشر أحدث البرامج التي لا تزال نماذج أولية ، قد تكون مكلفة لتشغيل الشركات الأقدم على نطاق واسع ، ولا تروق للشركات المعقدة. كسب المال للأشخاص الذين لا يفعلون أي شيء حقًا. إذا اتبعت هذا الكتاب عن كثب ، فستحتاج إلى كتابة رمز ورمز بحث وإنشاء تطبيقاتك الخاصة ، وسوف تجني أموالًا مما تفعله. سأجني المال من هذا الكتاب ، حتى في المراحل المبكرة ، لأنه يحتوي على معلومات يحتاجها الناس ويريدون القراءة ، ويشتري بالفعل عند شراء أو استخدام تطبيقاتي. لن يقوم هذا الكتاب بإنشاء تطبيق لك ، لكنه سيوجهك في الاتجاه الصحيح ويسددك بالأدوات التي تحتاجها والمهارات والنصائح التي ستسهل نجاحك في بناء البرامج للويب ، مع كل سطر من سطر رمز ستحتاج إلى الكتابة كمثال ، على استعداد للتجميع معًا في البرامج أنت ومؤيديك ، الضيوف ، العملاء ،يرغب Riends والأسرة والزوار والمقاولين وأفراد الإنترنت في استخدام ودعم. ماذا ستتعلم: سيعلمك هذا الكتاب كيفية إنشاء وبيع البرامج ، والبرامج الوظيفية ، والمفيدة حقًا ، وتسجيل الوسائط ، وميزات أمان مثل التعرف على الوجه ، ومسح باركود المنطقة القابل للقراءة ، وواجهة برمجة تطبيقات الويب للمصادقة وتسجيل الفيديو وصورها ، وتبادلها ، وتبادل الرسائل مثل Bluetooth وبالقرب من التواصل الحقل (NFC). سيعلمك هذا الكتاب كيفية استخدام جهاز كمبيوتر متصل بالشبكة ، مع التركيز على Debian Linux ، وكيفية إنشاء رمز Bash لجعل تثبيت ودعم البرنامج الخاص بك نسيمًا سلسًا آلي الأشياء بشكل جيد باستخدام أنماط CSS مع Bootstrap ، وتمكين تسجيلات تسجيل الدخول والتفاعل من خلال الأجهزة المربوطة بالشبكة ، وبناء الوسائط التفاعلية والشبكة مع مواقع الويب الأخرى لتقديم ميزات أمان مثل الرسائل النصية للتحقق أو غيرها الأغراض ، المسح الضوئي ، اعتدال الصور والفيديو ، البياناتRansactions للحفاظ على آمنة البرنامج ، ومعالجة الدفع ، وتداول العملة المشفرة ، والمهام غير المتزامنة ، وأكثر من ذلك. سوف تتعلم كيفية إنشاء أجهزة Bluetooth الخاصة بك ، مع البطاريات والشاحن وموكنتات متحكم ودوائر ومحركات وأجهزة الاستشعار ، باستخدام اللحام والأسلاك والمواد المطبوعة ثلاثية الأبعاد بالإضافة إلى المواد المصبوب. سأعرض مبادئ التصميم ثلاثية الأبعاد المطبقة على التصنيع المضافة وصنع الأدوات والموت ، لذلك يمكنك تصنيع أجهزة الأجهزة المضمنة الخاصة بك مع بطاريات متكاملة ، شواحن ، دوائر إلكترونية ، والمخرجات الوظيفية. وتواصل معها مع البلوتوث والويب. على وجه التحديد ، سنقوم بفحص دراستين للحالة ، ومدلك تهتز وسلاح ناري محلي الصنع ، كلاهما مبرمج في OpenScad ، والذي يتوفر كواجهة رسومية أو سطر أوامر يمكن دمجه في شبكة ويب للحصول على نتائج أسرع. سوف تتعلم كيفية إنشاء موقع ويب ونشره من الألف إلى الياء دون أي خبرة سابقة ، وجعله وظيفيًا وآمنًا وجميلًا ومفيدًا وأكثرعملي بشكل كبير. سوف تتعلم كيفية استخدام التعلم الآلي ورؤية الكمبيوتر لجعل موقع آمن وأكثر عملية ، وتسجيل الفيديو والصوت من موقع الويب الخاص بك ، والتبرع بصوتك ، وصنع الموسيقى وتعديل الصوت لإنشاء عينات مفيدة ، وكيفية اختراق الضوضاء عن طريق الاستفادة من مواقع الويب الأخرى لإنشاء أفضل شبكة محتملة من مواقع الويب التي يمكنك ربطها مباشرةً بمشاركة جميع المعلومات المفيدة التي تقدمها ، والأهم من ذلك أن تجلب الأشخاص إلى البرامج وأعمالك. سيركز هذا الكتاب بشكل كبير على الوسائط والأمان والتعلم الآلي ، والتي هي المكونات الثلاثة الرئيسية التي ستساعدك على بناء برامج مفيدة للويب من خلال إشراك المستخدمين المناسبين وفصل العناصر الخاطئة بطريقة واقعية وعملية ، وعملية ، يديك والانخراط في حين أيضا تلقائي ، وقوي. يعلم هذا الكتاب Unix ، وتحديداً Debian (Ubuntu) ، و Bash Shell ، و Python ، و HTML ، و CSS ، و JavaScript ، وعدد من حزم البرامج المفيدة لـمثل الطلبات ، بالإضافة إلى برنامج Bash مفيد مثل Git و FFMPEG. سأعلمك أيضًا كيفية تداول العملة المشفرة تلقائيًا ، وأخذ مدفوعات في العملة المشفرة أو من بطاقات الخصم العادية مع دفع زوارك حصة من إيراداتك إذا اخترت القيام بذلك. سأعلمك كيفية كسب المال من موقع الويب الخاص بك من خلال الإعلان أيضًا ، وكيفية إعداد تطبيقك لمحركات البحث وجعله سريعًا ، ومرتبة في الترتيب الأول لما سيبحثه عملاؤك للعثور عليك ، وترتيب أكبر عدد ممكن عمليات البحث قدر الإمكان. سأعلمك كيفية بيع البرامج الخاصة بك ، والإعلان عنها ، والناشئ للعملاء الذين يبحثون عن خدماتك ، وأن تصنع اسمًا لنفسك على الإنترنت من خلال السبل الموجودة بالفعل ، غير مكلفة ، وتعمل بشكل جيد. سأعلمك كيفية حفظ بياناتك على أجهزة الكمبيوتر السحابية التي تعمل من أجلك وحفظ بياناتك بثمن بخس ، وكيفية تخطيط وإنشاء موقع ويب يقوم بما يريده المستخدمون وما تريده ، وكيفية إبقاء المستخدمين مشاركينإن نقر على هواتفهم على هواتفهم بإشعارات ، والبريد الإلكتروني ، والرسائل النصية ، والمكالمات الهاتفية ، والمزيد من السبل لإعادة المستخدمين إلى موقع الويب الخاص بك تحت تصرفك خلف النقر على زر مضمون لك فقط. سيركز هذا الكتاب على التطبيق العملي لنشر وسائل الإعلام وتوزيعها بكميات كبيرة ، من نص إلى صور إلى مقاطع فيديو إلى صوت ، وإحداث انطباع جيد على المستخدمين النهائيين (زبائنك) ، وبيع نفسك بأي طريقة تقوم بها من أجل الإنشاء موقع ويب ، وهو تطبيق يمثل لك وأنت فقط ، ويجعلك وبرنامجك وشركتك تبدو جيدة بأفضل طريقة ممكنة. سوف تتعلم أيضًا بعض النصائح والحيل مني ، من نصائح الترميز ، والغرور العملي مثل الماكياج والتصوير الفوتوغرافي ، والنمذجة والتمثيل ، وأكثر من ذلك ، والتي ستكون مهمة لتصوير نفسك وشركتك في أفضل ضوء ممكن باستخدام جميع الأدوات المتاحة لك أثناء توزيع أكبر قدر من المحتوى الذي تحتاجه عبر توازن صحي من المنصات لجلبكE إلى الثمار دون جهد أو عمل أو أموال أكثر مما هو ضروري. يُطلق على هذا الكتاب اسم "التعلم العملي والأمان القائم على الويب القائم على الويب" لسبب ما: إنه يتعامل مع التعلم إلى التعليمات البرمجية ، وتحديداً على الويب ، وتحديداً مع التركيز على الأمان ، من وجهة نظر عملية ، مع أمثلة على رمز العمل الذي يخدم الأغراض العملية الموضحة في النص. يشمل مكون التعلم في هذا النص أيضًا التعلم الآلي ، والرمز الذي سأوضح لك كيفية التشغيل للويب الذي سيتعامل مقاييس التنبؤ التي يتم الحصول عليها من الصور ، مثل طبيعة الصورة كصورة أصيلة محددة للكمبيوتر أو نسخة بصرية (صورة لصورة أو صورة مطبوعة). يعد التعلم الآلي مهمًا جدًا عندما يتعلق الأمر بأمان الويب وأمان البرامج ، لأنه يمكن أن يتكاثر المهام التي كانت مستحيلة على خلاف ذلك. جهاز الكمبيوتر الخاص بكقم بتسجيل الدخول مع رمز المرور ، ولكن قد يكون من الآمن استخدامه إذا قام بتسجيل الدخول مع وجهك. يمكنك جعل جهاز كمبيوتر خادم آمنًا ، وهو جهاز كمبيوتر يطلب منك عادة اسم مستخدم ورمز مرور وتسجيل الدخول ، ربما مع رمز تأكيد لكل تسجيل دخول جديد أو عنوان IP جديد ، ولكن إذا كنت تقوم ببناء على نطاق واسع ، من السهل القيام به الاستخدام ، البرمجيات الآمنة والقوية بشكل أساسي ، قد يكون هذا كافيًا. إن ربط البرنامج الخاص بك عن كثب إلى برنامج شخص آخر ، مثل خدمة البريد الإلكتروني أو خدمة الرسائل النصية ، لا يكفي لجعل برنامجك آمنًا ، أو أي موقع تستخدمه). أي شخص يبني برامج آمنة لا تشوبها شائبة لديه بعض الإحساس بما ينطوي عليه هذا. البرمجيات غير آمنة بطبيعتها لأن الأجهزة والحسابات التي نستخدمها للوصول إليها ليست دائمًا تحت تصرفنا ، فقد تكون في أيدي أي شخص يعاني من نية للبرنامج ، وبالتالي قد يشكلون خطرًا على البرنامج نفسه. هذا شيء من محور هذا الكتاب. كمبيوتر متصل بالشبكة افتراضيًاتم تأمينه باستخدام رمز مفتاح طويل ، يسمى و SSH أو Secher Shell ، ويتم تأمينه بشكل أفضل مع خادم ويب ، لأن خادم الويب يوفر الوصول المفتوح وكذلك أدوات الأمان الفنية التي تعمل على الخادم نفسه. يتمتع خادم الويب بإمكانية الوصول إلى متصفح الويب الخاص بالمستخدم ، والذي يمكن القول إنه أقوى جزء من جهاز المستخدم ، لأنه المكان الذي يمكن للمستخدم فيه الوصول إلى البرامج الشباعية. يمكن لمجموعة الأدوات هذه تقديم نص ، وصفحات الويب التي تراها ، ويمكنها أيضًا تسجيل الصور والصوت والفيديو (مثل صورة للوجه أو معرف الحالة) ، ويمكنها القراءة والكتابة إلى أجهزة الراديو Bluetooth ، ويمكنها القراءة والكتابة إلى الحقل القريب علامات الإرسال والاستقبال ، وبطاقات المفاتيح غير المكلفة ، و FOBs ، والملصقات ، والخواتم ، وحتى زراعة الرقائق مع أرقام تسلسلية فريدة يمكن قراءتها وكتابتها مع البيانات التي تم إنشاؤها والتحقق من صحتها بواسطة خادم ويب مرتبط بموقع الويب. باستخدام جميع الأدوات الموجودة تحت تصرفك ، مع هذا الكتاب ، سوف تجهز نفسك بالمعرفة لإنشاء موقع ويب آمن ، وعمومانظام كمبيوتر متصل بالشبكة يناسبك ، ويقوم بتقديم مزايدة ، ويبدو ويشعر بالصواب. من أين تبدأ: مرحبًا بك في تخطي القسم الذي أبدأ هذا الكتاب به ، أو أي قسم ، إلى الكود الدقيق الذي تحتاجه ، خاصة إذا كان لديك خبرة في الترميز قبل أو أي من الأدوات المذكورة أعلاه سأصف بالتفصيل في هذا الكتاب وكذلك توثيق حالات الاستخدام والأمثلة العملية عليها. إذا لم يكن لديك خبرة في كتابة التعليمات البرمجية ، فإنني أوصي بشدة بقراءة كل هذا الكتاب ، وأوصي بشكل خاص بقراءة الأقسام السابقة ، للتأكد من أن هذا الكتاب مناسب لك. إذا لم يكن هذا الكتاب مناسبًا لك ، ففكر في تقديمه إلى صديق أو قريب قد يكون مهتمًا بالتعرف على تطوير الويب بأنفسهم ، وحتى التفكير في استعارة الأمر والتعلم منه لملء الفجوات التي فشلت فيها كملف المعلم ، أو المعلمين الآخرين فعل قبلي. ابدأ من أين تريد ، سيكون كل جزء من هذا الكتاب مفيدًا إذا كنت تنوي بناء مفيدPP ، واعتبر أنه تم تصميم أفضل التطبيقات مع وضع المستخدم النهائي في الاعتبار: تعرف على عميلك. أنت تعرفني الآن ، أنت تعرف هذا الكتاب ، وأنت مستعد للبدء. للبدء ، احصل على جهاز كمبيوتر (حتى أرخص كمبيوتر محمول من متجر مربع أو Amazon أو أعمال مكتب قديم ، وقم بإعداده بطريقة تناسبك. كيف تقرأ هذا الكتاب: يبرز النص ، ويشير إلى أن النص ينتمي إلى موجه الأوامر ، حيث ستكتب الرمز الذي تقوم بتشغيله. تركز موجه الأوامر بشكل كبير على لوحة المفاتيح ويتطلب القليل من النقر ، مما يسرع سير العمل الخاص بك وجعل الأمور أسهل عليك. ابدء: دعنا نغوص فيها. سنبدأ ببناء رمز على جهاز محلي ويبدأ دون إنشاء موقع ويب متصل بالإنترنت. هذا أكثر أمانًا للبدء ، ولا يكلف شيئًا ، وهو سهل بالنسبة لك. اعتمادًا على نظام التشغيل الخاص بك ، سيكون الدخول إلى قذيفة باش مختلفة قليلاً. لنظام التشغيل Mac OS ، أوصي بتثبيت جهاز افتراضي في هذه المرحلة ، حيث ستحصل على أكبر قدر من التوافق معالجهاز الظاهري. يمكن لمقدمي الخدمات المختلفة مثل VirtualBox و Paralells تشغيل جهاز افتراضي لك ، على الرغم من أنه من الممكن أيضًا تثبيت Ubuntu مباشرة على الجهاز ، إذا كنت تفضل استخدام بيئة أصلية موصى بها من أجل إنشاء تجربة سريعة ومتبسطة. إذا كنت تستخدم Linux أو Windows ، وهو ما أوصي به ، فيجب أن يكون من السهل جدًا إنشاء مشروع. افتح المحطة الخاصة بك ، واضبط التحجيم كما تراه مناسبًا ، وابدأ في اتباع الخطوة 2. إذا كنت تستخدم Windows ، فيرجى اتباع الخطوة 1. الخطوة 1: - مستخدمي Windows فقط في Windows ، فتح موجه الأوامر كمسؤول ونوع WSL - التثبيت الخطوة 2: - تابع هنا ، أو تخطي الخطوة 1 إلى هنا إذا كنت لا تستخدم Windows في محطة مفتوحة ، (اعتمادًا على نظام التشغيل الخاص بك ، يسمى Ubuntu في Windows أو Terminal في Mac أو Linux ، أو اسم مشابه) ، ابدأ بإنشاء مشروع. نفعل هذا مع أمر mkdir ، والذي ينشئ دليلًا. إذا كنت بحاجة إلى إنشاء دليل لتخزين مشروعك ، وهو أمر موصى به ، استخدمأمر CD للتغيير إلى الدليل و و القرص المضغوط/المسار/إلى/الدليل - المسار هو المجلدات (الملفات) التي تسبق دليل الوجهة الخاص بك ، مسارك الافتراضي هو ~ أو/home/اسم المستخدم (حيث اسم المستخدم هو اسم المستخدم الخاص بك). للتغيير إلى الدليل الافتراضي ، اكتب قرص مضغوط أو قرص مضغوط ~ مثال MKDIR - استبدل "مثال" باسم الدليل الآن لديك دليل عمل لمشروعك. كونه من المهم للغاية حفظ هذا الدليل في حالة حاجة إلى التبديل إلى جهاز مختلف أو نشر الرمز الذي تكتبه بحيث يكون جاهزًا للويب ، سنقوم بإنشاء برنامج نصي لإعداد الدليل الخاص بك في الخطوات القليلة التالية. لكن بناء برنامج نصي يأخذ القليل من التعليمات البرمجية ، ويجب أن يكون الكود أتمتة ليكون مفيدًا قدر الإمكان. لذلك دعونا نبني نصًا لإنشاء البرامج النصية أولاً. لنبدأ بإنشاء البرنامج النصي وجعله قابل للتنفيذ. سنستخدم sudo و chmod و touch لهذا ، واتصل بالبرنامج النصي


sudo touch /usr/bin/ascript
sudo chmod a+x /usr/bin/ascript
sudo nano /usr/bin/ascript
الآن لقد أنشأنا البرنامج النصي ، وجعلناه قابلاً للتنفيذ ، ونحن مستعدون لتحريره. Nano هو محرر نصوص يتيح لك تحرير النص دون النقر ، وهو أسهل بكثير من استخدام واجهة مستخدم رسومية. لتحرير ملف مع Nano ، استخدم Nano ثم المسار إلى الملف. لإنشاء برنامج نصي يصنع البرنامج النصي ، يشبه إلى حد ما صنع البرنامج النصي في المقام الأول. سنستخدم نفس الرمز كما هو مذكور أعلاه ، استبدال اسم البرنامج النصي ، "Ascript" بمعلمة وسيطة ، $ 1. هذا يتيح لنا الاتصال بالبرنامج النصي عن طريق كتابة Supo Ascript Newscript ، وعندها يمكننا إنشاء أي برنامج نصي جديد عن طريق استبدال "Newscript" باسم البرنامج النصي الخاص بك. يجب أن يبدو الرمز في نانو:

sudo touch /usr/bin/$1
sudo chmod a+x /usr/bin/$1
sudo nano /usr/bin/$1
ولإغلاق Nano ، يمكننا الضغط على مفتاح التحكم والضغط على X ، ثم Y للدلالة على أننا نحفظ الملف ، وضرب الإرجاع. الآن بدلاً من كتابة هذه الأوامر الثلاثة لتحرير البرنامج النصي ، سنكون قادرين على كتابة Succript Ascript لتحرير البرنامج النصي مرة أخرى. هذا يعمل! ويمكن تشغيل أي نص جديد بسهولة عن طريق تسميته في القشرة. دعنا نقوم بحفظ عملنا الآن: دعنا نكتب نصًا احتياطيًا لحفظ البرنامج النصي الجديد الخاص بنا ثم نسخه في دليل مشروعنا ، مع دعم البرنامج النصي الاحتياطي أيضًا.

sudo ascript backup
الآن ، في نانو:

sudo cp /usr/bin/backup /path/to/directory/
sudo cp /usr/bin/ascript /path/to/directory/
WHERE/to/to/directory هو المسار إلى المشروع الذي أنشأته مع MKDIR. في وقت لاحق سوف نتعلم كيفية نسخ مسارات التكرار مثل هذه مع حلقة وقائمة ، وهي رمز أقل ، ولكن الآن لنبقيها بسيطة ولدينا بضعة أسطر. لتشغيل هذا البرنامج النصي ونسخ الرمز الاحتياطي الخاص بك ، احفظ الملف في Nano باستخدام Control+X ، Y و Retring ، واكتب أدناه في قذيتك

backup
إذا تمت مطالبتك على الإطلاق بكلمة مرور أثناء قراءة هذا الكتاب والمتابعة في القشرة ، فيرجى إدخال كلمة مرور المستخدم بشكل صحيح ، فسيكون لديك ثلاث محاولات قبل أن تحتاج إلى إعادة تشغيل الأمر. يمكنك استخدام الأسهم لأعلى ولأسفل لإعادة تشغيل الأوامر وتحريرها ، إذا كنت بحاجة إلى تشغيل أي شيء مرتين. اضغط البسيط لأعلى ولأسفل بشكل متقطع لتحديد أمر ، قبل تحرير الأمر مع الأسهم اليمنى ، والحذف المفتاح وكذلك لوحة المفاتيح ، وتشغيله مع الإرجاع. مبروك! لقد تمكنت من إنشاء برنامج نصي احتياطي رائع يدعم نصين مهمين في دليل العمل الخاص بك. قد نقوم بتحريك الأشياء لاحقًا مع تقدم المشروع ، لكن هذا يعمل الآن. دعنا ننتقل إلى النسخ الاحتياطي في السحابة ، وسنستخدم GitHub لهذا (على الرغم من وجود العديد من حلول GIT الأخرى للنسخ الاحتياطي ، فهي كل شيء على وشك.) البرنامج كما تصنعها إلى خادم ، بينمايمكّنك أيضًا تنزيل نسخ كاملة من برنامجك خلف كلمة مرور أو مفتاح. من المفيد في حفظ البرنامج الخاص بك ، خاصة وأننا نراجع إلى حالات Linux المضمنة التي تنكسر أحيانًا عند فشل سطر واحد من التعليمات البرمجية ، مما يتركك مغلقًا بينما قد لا يتم نسخ الكود الخاص بك إذا لم تحصل على فرصة لدعمه UP تلقائيًا ، والتي سنغطيها. إذا كنت لا تستخدم بالفعل جهازًا افتراضيًا لـ Ubuntu في هذه المرحلة ، فأنا أوصي باستخدام جهاز افتراضي Ubuntu في هذه المرحلة لأنه سيجعل حياتك أسهل عند تثبيت جميع الحزم اللازمة من أجل إنشاء موقع ويب عام العمليات على جهاز الكمبيوتر الخاص بك. سننقل الرمز إلى خادم ويب في المستقبل القريب ، لكننا نريد التأكد هذا. إذا كنت لا تزال ترغب في استخدام نظام التشغيل Mac OS ، فأنت مرحب بك للبحث عن وتثبيتE الحزم الضرورية عبر الإنترنت ، ولكن قد لا تكون هناك بدائل لكل حزمة سيغطيها هذا الكتاب أو السلسلة. دعنا نضيف بعض الأوامر لارتكاب عملنا باستخدام البرنامج النصي الاحتياطي عن طريق تشغيل الأمر succript

# ...
git add –all
git commit -m “backup”
git push -u origin master
مرة أخرى ، السيطرة على X للحفظ. الآن نحتاج إلى القيام بتكوين مرة واحدة لهذا المشروع. نظرًا لأنه سيكون قريبًا مشروع GIT ، لا نحتاج إلى كتابة كل أمر في كل مرة ننشر فيها من مستودع GIT ، لكننا سنحصل على تعليق هذا عندما نكتب نصوص النشر الخاصة بنا. للبدء ، دعونا نتأكد من أننا في الدليل الصحيح وتهيئة مستودع GIT وإنشاء مفاتيح SSH.

cd /path/to/directory
git init
git branch -m master
ssh-keygen
بعد أن نكتب SSH-Keygen ، يجب حفظ المفتاح الجديد في المجلد المنزلي تحت مجلد يسمى .ssh. ويسمى id_rsa.pub. دعنا نجد هذا المفتاح وننسخه. لرؤيتها ،

cd ~
cat .ssh/id_rsa.pub
انسخ النص الذي يتم إرجاعه بواسطة الأمر الأخير ، وقم بإنشاء حساب مع مزود GIT الخاص بك (من الناحية المثالية github) ، قبل إضافة مفتاح SSH إلى حسابك. بمجرد أن يكون لديك حساب ، انقر فوق القائمة العلوية اليمنى وأدخل الإعدادات ، قبل إضافة مفتاح SSH في مفاتيح SSH و GPG تحت الوصول في القائمة. حدد إضافة مفتاح SSH وأضفك عن طريق لصقه وإعطائه عنوانًا ، قبل حفظه والعودة إلى Github لإنشاء مستودع جديد. هذا مشابه لمقدمي خدمات GIT الآخرين ، ستحتاج إلى قراءة وثائقهم. في تكوين المستودع الجديد ، امنح مستودعك اسمًا وصفيًا وقرر ما إذا كنت تريد نشره ، والتأكد من عدم تكوين أي ملفات لإدراجها حتى الآن. بمجرد إنشاء المستودع ، انسخ Clone باستخدام عنوان URL SSH ، ولصقه في الأمر التالي.

git remote add git://… (your remote URL)
الآن يمكنك العودة إلى مستودعك باستخدام القرص المضغوط ، وستكون على دراية بهذا. جرب البرنامج النصي الاحتياطي الآن مع النسخ الاحتياطي عظيم! الآن يمكننا حقًا الحصول على الترميز. دعنا نثبت Django الآن بعد أن حصلنا على فهم جيد على Bash و Git. سيسمح لنا Django بتركيب برنامجنا تلقائيًا ، يمكن لـ Bash القيام بذلك أيضًا ، لكن يجب أن يكون لدى Django تطبيق أكثر أمانًا (يمكن تعطيله وتكوينه بسهولة أكبر). لتثبيت البرامج في Ubuntu ، سنستخدم الأمر sudo apt-get. أولاً ، دعنا نقوم بتحديث وترقية البرنامج الذي كان لدينا بالفعل. يمكن القيام بذلك مع تحديث Sudo APT-GET و Sudo APT-GET UPGRADE -y. بعد ذلك ، دعنا نثبت Python وبيئتنا الافتراضية ، موطن الكود الخاص بنا ، مع الأمر التالي: Sudo APT-GET تثبيت Python-IS-Python3 Python3-Venv هذا هو كل ما تحتاجه للذهاب مع Django من حيث تثبيت البرامج في مثيل Ubuntu. بالنسبة لنظام التشغيل Windows و Linux ، يجب أن يكون هذا واضحًا إلى حد ما ، ولكن قد ترغب في تثبيت جهاز افتراضي وLinux عليها باستخدام بيئة افتراضية مجانية أو مدفوعة مثل VirtualBox أو Paralells سطح المكتب وإعادة إنشاء الخطوات المذكورة أعلاه من أجل إعداد بيئة Ubuntu. يعد Ubuntu أمرًا بالغ الأهمية في هذه الحالة لأنه البرنامج الذي تقوم به مواقع الويب ويمكّنها من استضافة مواقع الويب مع جميع البرامج المذكورة أعلاه. دعنا نحفر في Django. في دليلنا مرة أخرى ، مع

python -m venv venv # يخلق البيئة الافتراضية حيث يتم تخزين الكود
source venv/bin/activate # ينشط البيئة الافتراضية
pip install Django
django-admin startproject mysite . # حيث Mysite هو المشروع الذي أبدأ به في دليلي الحالي.
لقد بدأنا Django للتو ، لأن Django يستضيف خادم الويب ويقوم بكل ما نحتاجه للحصول على موقع ويب محلي أساسي. الآن بعد أن تم تثبيت Django ، دعنا نقوم بتحرير الإعدادات قليلاً لجعلها تعمل كيف نحتاج. أولاً ، دعنا ننشئ تطبيقًا جديدًا

python manage.py startapp feed
ستلاحظ أن التطبيق الأول يسمى التغذية. يجب أن يطلق على التطبيق ما تريد ، وسننشئ تطبيقات جديدة ، ولكن يجب أن يكون اسم كل تطبيق ثابتًا في كل مرة يتم فيها الرجوع إلى التطبيق في الرمز. لإضافة تطبيق جديد ، سنقوم دائمًا بتحرير الإعدادات. قم بالتحديد في الدليل الآخر الذي تم إنشاؤه ، والذي تم إنشاؤه في startProject ، في الآخرة. باستخدام نانو ،

nano app/settings.py
في الإعدادات ، ابحث عن installed_apps وفصل [] إلى 3 أسطر. باستخدام أربع مسافات على خط الوسط الفارغ ، أضف "التغذية" ، أو اسم تطبيقك. يجب أن يبدو هذا القسم من الإعدادات.

INSTALLED_APPS = [
    'feed',
]
قبل أن ننسى ، دعونا نختبر أن Django يعمل. باستخدام الأمر Python Manage.py Runserver 0.0.0.0:8000 ، يمكننا تشغيل الخادم ثم التنقل في متصفح ويب على الكمبيوتر الذي يعمل على تشغيل الرمز إلى http: // localhost: 8000 وشاهد مثال على الويب (يعمل!) ترك الخادم مع التحكم C ، مثل أي أمر آخر. الآن ، دعنا نحفر في كتابة بعض كود بيثون. لدى Django ثلاثة مكونات رئيسية ، وكلها تديرها رمز بالكامل. تسمى المكونات النموذج والعرض والقالب ، وكل منها على مستوى أعلى وأقل على التوالي قبل تسليم صفحة الويب إلى المستخدم. النموذج هو الرمز الذي يخزن المعلومات في قاعدة البيانات لاسترجاعها وفرزها وتقديمها. يقرر العرض كيفية تقديم النموذج ومعالجته وتعديله ، وسوف يستخدم كل عرض تقريبًا نموذجًا مباشرة. القالب هو رمز HTML مع بعض الأجراس والصفارات الإضافية التي تسمى لغة القالب. يتم تقديم القالب من خلال العرض حيث تمتلئ برمز Python وسياق مثل النماذج والمعلومات (أوتار أو أعداد صحيحة) من العرض. لدى Django مكونات أخرى أيضًا ، بما في ذلك على سبيل المثال لا الحصر: الإعدادات ، التي تقوم بتكوين التطبيق كما ناقشنا. عناوين URL ، وهي أنماط يتبعها المستخدم للوصول إلى أجزاء محددة من تطبيق الويب. النماذج ، التي تحدد كيفية معالجة المعلومات التي يتم إرسالها إلى الخادم وتقديمها إلى قاعدة البيانات وكذلك للمستخدم. هذه هي أساس معالجة المعلومات على جانب الخادم ، ويمكنها قبول أي نوع من المعلومات التي يخزنها الكمبيوتر ، وأبرزها سلاسل النص ، والأرقام ، والطقس الحقيقي/الخاطئ (عادة مربعات الاختيار). القوالب ، التي هي رمز HTML ولغة القالب وسدّع الفجوة بين Python و HTML ، مما يعني أنه يمكن تقديم معلومات Python كرمز HTML الذي يمكن لأي شخص الوصول إليه ويمكنه تأمين موقع ويب مع وصول مقيد ، مع جعل رمز Python متاحًا إلى الويب والمفيد لمجموعة متنوعة من الأغراض على جهاز بعيد لاeed لتكون بالقرب من الخادم. الملفات الثابتة ، والتي عادة ما تكون JavaScript ومكتباتها التي يخدمها الخادم وترتبط بها القالب. ملفات الوسائط ، التي يقدمها الخادم أو يتم استضافتها خارجيًا ، أو مكتوبة للتو إلى الخادم قبل معالجتها ونشرها على خادم آخر (دلو) للاستضافة. الوسيطة ، وهي أجزاء من التعليمات البرمجية التي يتم تشغيلها في نفس الوقت مثل كل عرض وتعتبر "مدرجة" في العرض. معالجات السياق ، التي تقوم بمعالجة سياق كل طريقة عرض وتستخدم لإضافة سياق إضافي. الاختبارات ، التي تؤكد أن المستخدم أو الطلب يمرر متطلبات معينة قبل تقديم العرض. المستهلكون ، الذي يملي كيف تتعامل WebSockets للاتصالات والاستجابة لها. المسؤول ، الذي يتم استخدامه لتسجيل النماذج بحيث يمكن معالجتها بالتفصيل في صفحة مسؤول Django ، حيث يمكن إعطاء قاعدة البيانات من خلال واجهة رسومية. الكرفس ، الذي يحدد المهام غير المتزامنة يمكن أن تبدأ أجزاء من رمز DjangoNning قبل الانتقال فورًا إلى المهمة التالية أو سطر الكود. يمكن أن يكون لدى Django العديد من المكونات الأخرى ، والتي سنناقشها بالتفصيل هنا. هناك الكثير من الطرق لجعل Django أكثر وظيفية ، وإضافة Websockets ، وهي قنوات اتصال سريعة وتبسيط ، والكرفس ، والتي تنفذ المهام غير المتزامنة ، وعدد كبير من البرامج الأخرى لتمديد Django ، وخاصة في وظائف العرض ، حيث معظمها يتم تنفيذ الرمز. تعتبر وظائف العرض مفتاحًا لأنها عادة ما تعلن كل جزء من التعليمات البرمجية المخصصة لنمط عنوان URL محدد ، أو قسم من الخادم. أولاً ، دعنا نستكشف وظائف العرض. تبدأ وظائف العرض بالواردات التي تشير إلى الكود الذي سيتم استخدامه في العرض ، ويتم تعريفه باستخدام تعريفات أو فئات الوظائف العادية. يتم تعريف أبسط المشاهدات بواسطة DEF تعريف الوظيفة ، وإرجاع httpresponse باستخدام قالب أساسي. لنبدأ بتحديد طريقة عرض أساسية لإرجاع النص "Hello World". تذكر أنه في كل مرة تضيفقم بتوضيح بيان مثل DEF ، إذا ، على الرغم من ذلك ، إلخ ، ستحتاج إلى إضافة 4 مسافات لكل من التعريفات السابقة التي ترغب في تطبيقها على وظيفتك. سوف ندخل في ما يعنيه كل من هذه قريبًا. من دليل موقعنا ، قم بتحرير ملف التغذية/views.py باستخدام nano وأضف الأسطر التالية إلى نهاية

from django.http import HttpResponse

def hello(request):
    return HttpResponse('hello world')
يستجيب HttPresponse من Django بسلسلة نصية ، يُشار إليها بالافتتاح والإغلاق. في كل مرة تقوم فيها بتمرير معلومات إلى وظيفة أو فئة ، مثل الطلب أو السلسلة ، ستحتاج إلى استخدام قوسين (وفتح وإغلاق). هذا ليس كل ما نحتاجه لرؤية وجهة نظرنا بعد. بالطبع ، لم نخبر الخادم عن مكان العرض بالضبط ، ما زلنا بحاجة إلى تحديد مسار يجب من خلاله عرض العرض. لنبدأ بتحديد مسار أساسي في app/urls.py ، وسنصل إلى مجموعات المسار لاحقًا. في App/urls.py ، أضف خطًا بعد بيانات الاستيراد بعد بداية استيراد العرض الذي أنشأناه للتو.

from feed import views as feed_views
الآن ، دعنا نحدد نمط العرض. تحتوي أنماط العرض على ثلاثة مكونات ، وهو مكون المسار ، والذي يخبر الخادم حيث يوجد العرض داخل الخادم (مسار عنوان URL الذي يكتبه المستخدم في شريط التنقل للدخول إلى صفحة الويب) ، ومكون العرض حيث يتم تحديد العرض ، و اسم ودود للعرض بحيث يكون من السهل استرداد نمطه عند العمل مع قالب ، خاصة بحيث يمكن تغيير اسمه وتحديثه إذا لزم الأمر لتوفير مساحة لعرض آخر أو الاستمتاع باسم أكثر منطقية. من المنطقي القيام بالأشياء بهذه الطريقة وأن تكون مرنًا ، لأن قاعدة بيانات الكود ستكون بيئة متغيرة باستمرار تحتاج إلى المرونة والارتجال من أجل أن تكون ذات قيمة وسهلة العمل معها. إليك ما سيبدو عليه عرضك ، يمكنك إضافة هذا إلى urlpatterns = [قسم App/urls.py. يتم تعريف نمط العرض مع المكونات الثلاثة الموضحة أعلاه ، ودالة تسمى المسار. أنماط عنوان URL الخاص بك هي قائمة ، لذا تأكد دائمًا من إنهاء كل عنصر فيهامع فاصلة ، لأن هذا يفصل كل واحد. يجب أن يذهب كل عنصر أيضًا على سطر جديد ، مرة أخرى مع أربعة مسافات قبله ، تمامًا مثل التطبيق في الإعدادات. سنقوم بتحديد المكون الأول من العرض بوظيفة سلسلة فارغة ، من أجل إنشاء طريقة عرض يتم تشغيلها على الدليل الجذر لخادم الويب. يجب أن يبدو عنوان urls.py الخاص بك الآن

from feed import views as feed_views

urlpatterns = [
    path('', feed_views.hello, name='hello'),
]
هذا هو الأساس لإنشاء موقع ويب مع Django ثابت تمامًا. من أجل إنشاء موقع ويب أكثر ديناميكية حيث يمكننا البدء في تخزين المعلومات ، مثل الصور ومقاطع الفيديو والصوت والمزيد ، سنحتاج إلى استخدام النماذج ، والتي سنستكشفها بعد ذلك. في الوقت الحالي ، دعنا نتحقق من التعليمات البرمجية الخاصة بنا وتشغيل الخادم. للتحقق من رمز الأخطاء ، قم بتشغيل:

python manage.py check
إذا كان هناك أي رسائل خطأ ، فيجب عليك مراجعة التغييرات التي أجريتها على تطبيقك بعناية ومعرفة ما إذا كان هناك أي شيء يجب إصلاحه ، مثل الفضاء الغريب أو الذي يفتقر إليه حذف الشخصية ، أو أي شيء آخر. عند قراءة رسالة الخطأ (إذا كان لديك واحد) ، يجب أن تكون قادرًا على رؤية المسار إلى ملف قمت بإنشائه أو تم تحريره مع رقم سطر ، لذا ابحث في هذا الملف والخط ومعرفة ما إذا كان يمكنك إصلاح أي شيء موجود . إذا كنت قد قمت بإصلاح المشكلة ، فقم بتشغيل الأمر أعلاه مرة أخرى. عندما يكون برنامجك جاهزًا للتشغيل ويعمل ، سترى الإخراج "تحقق من عدم تحديد أي مشكلات". أنت الآن مستعد للذهاب. قم بتشغيل الخادم مع:

python manage.py runserver 0.0.0.0:8000
افتح الآن متصفح الويب وانتقل إلى http: // localhost: 8000. يجب أن ترى النص الذي يتم إرجاعه في قوسين واقتباسات وظيفة httpresponse في عرضك. هذا مجرد مثال أساسي ، ولكن إذا وصلت إلى هذا الحد ، فأنت تفهم أساسيات كيفية عمل Linux و Bash و Python و Django. دعنا نتعمق في بعض نمذجة قاعدة البيانات ، واستكشف قوة فئة Python في تخزين المعلومات. بعد ذلك ، سنبدأ في الحصول على قبضة على HTML و CSS قبل أن نجعل موقعنا مميزًا تمامًا ومرنًا وآمنًا باستخدام JavaScript والتعلم الآلي. يتم تخزين الفصول في الطرز. باستخدام nano ، تحرير التطبيق/models.py وأضف فئة جديدة. يتم تعريف الفئة مع تعريف الفئة ويتم تمريرها فائقة ترثها ، في هذه الحالة على طراز. يأتي اسم الفصل بعد تعريف الفئة ، وبعد استخدام تعريف الفئة A: (القولون) ، قبل الإشارة إلى السمات وتعريفات الوظائف المرتبطة بالفئة أدناه. صفنايحتاج إلى معرف يمكننا استخدامه لاسترداده والحفاظ عليه فريدًا ، ويحتاج أيضًا إلى حقل نص لتخزين بعض المعلومات. في وقت لاحق ، يمكننا إضافة طابع زمني أو ملفات أو منطقية (تعاريف حقيقية أو خاطئة يمكن أن تساعد الكود لدينا في اتخاذ قرارات بشأن ما يجب القيام به مع النموذج ، ويمكن استخدامه لفرزه) ، وهو مثيل لربط النموذج مع المستخدم المسجل في الخادم ، وأكثر من ذلك. دعونا نفشل الرمز

from django.db import models # الاستيراد المستخدم لتحديد صفنا وسماتها

class Post(models.Model): # تعريف فصلنا نفسه
    id = models.AutoField(primary_key=True) # معرف نموذجنا ، وهو مفتاح تم إنشاؤه تلقائيًا يتيح لنا الاستعلام عن النموذج ، والحفاظ عليه فريدًا ، وهو مفيد عندما نحتاج إلى التفاعل مع النموذج بمجرد إنشاءه.
    text = models.TextField(default='') # السمة المتاجر الخاصة بنا ، في هذه الحالة ، بعض النصوص ، تتخلف عن سلسلة فارغة.
أغلق وحفظ الملف كما فعلنا من قبل لإنهاء. هناك العديد من الحقول والخيارات الأخرى التي سنستكشفها عندما نقوم بتحديث هذه الفئة مع تطور تطبيقنا ، ولكن هذه هي الضروريات الأساسية لإنشاء تطبيق لنشر بعض النص. ومع ذلك ، لن يعمل هذا النموذج بمفرده. كما هو موضح من قبل ، سنحتاج إلى عرض مخصص ونمط عنوان URL المخصص لجعل هذا النموذج يعمل ، وسنحتاج أيضًا إلى نموذج مع قالب. دعونا نستكشف النموذج أولاً. لتحديد نموذج ، تحرير التطبيق/forms.py مع nano وأضف الأسطر التالية. سنحتاج إلى اثنين من الواردات ، فئة النماذج الخاصة بنا ، وكذلك النموذج الذي أنشأناه (feed.models.post) ، وتعريف فئة مشابه للنموذج ، وحقل جنبًا إلى جنب مع. يمكن أن يكون للنموذج أيضًا وظيفة تهيئة تضعها بناءً على المعلومات في الطلب أو النموذج أو غير ذلك ، وسنستكشف هذا لاحقًا. نماذج النماذج مفيدة للغاية لأنها يمكنها إنشاء نموذج أو أيضًا تحرير نموذج ،لذلك سوف نستخدمها لكليهما. دعونا نحدد واحدة في forms.py

from django import forms
from feed.models import Post

class PostForm(forms.ModelForm):
    text = forms.CharField(widget=forms.Textarea)
    class Meta:
        model = Post
        fields = ('text',)
هذه هي أساسيات شكل النموذج والنموذج. يمكن استخدام نموذج النموذج هذا لإنشاء إنشاء منشور أو تحريره ، وتغيير النص الذي يحتوي عليه. سننظر في دمج هذا النموذج في عرض التالي. أولاً ، دعنا نجعل الترحيل ونقلل قاعدة البيانات حتى يتمكن الكود لدينا من التفاعل مع النموذج عند تشغيله. للقيام بذلك ، قم بتشغيل الأوامر التالية:

python manage.py makemigrations
python manage.py migrate
سيستغرق التنفيذ دقيقة واحدة ، ولكن بمجرد قيامه بذلك ، سيسمح لك بالوصول إلى النموذج في طرق العرض أو الوسيطة أو في أي مكان آخر في البرنامج. دعنا نستمر من خلال إلقاء نظرة على حيث يمكننا رؤية نموذجنا. تحرير التغذية/views.py وأضف الكود التالي ، كما لوحظ. لن تحتاج إلى إضافة أي شيء بعد علامة # ، هذا الرمز هو التعليقات المستخدمة للدلالة على معلومات حول الرمز. سنبدأ باستيراد نموذجنا في طرق العرض ، وإضافته إلى سياق يمكننا فيه تقديمه في قالب كقائمة للعرض. بعد ذلك ، سنضيف قالبًا حيث يمكننا تقديم النموذج والنموذج باستخدام زر لإنشاء كائن جديد استنادًا إلى النموذج ونشره إلى الخادم. هذا يبدو معقدًا ، لذلك دعونا نأخذ الأمر خطوة بخطوة. قبل أن ننتهي من العرض ، دعنا ننشئ قالبًا يجعل النموذج فقط والتأكد من أننا نستطيع رؤيته عن طريق إنشاء منشور جديد في القشرة. إليك كيف يجب أن يبدو هذا الرأي:

from feed.models import Post
from django.shortcuts import render, redirect
from django.urls import reverse

def feed(request):
    posts = Post.objects.all() # الاستعلام عن جميع المنشورات في قاعدة البيانات حتى الآن
    return render(request, 'feed/feed.html', {
        'posts': posts,
    })
كل هذا يبدو بسيطًا جدًا حتى نصل إلى الأسفل. التقديم ، القيمة التي يتم إرجاعها بواسطة الوظيفة بدلاً من استجابة HTTP مثل المثال السابق ، تأخذ دائمًا طلبًا كأول إدخال لها ، تقبل سياقًا (في هذه الحالة المشاركات في قاعدة البيانات) ، والتي يمكن تقديمها الآن في القالب ، ويعيد القالب المحدد في الوظيفة. سيكون القالب مستند HTML مع القليل من لغة تسمى Jinja2 ، والتي تجعل معلومات Python في HTML. للبدء في إنشاء قوالب ، قم بعمل دليلين في التغذية.

mkdir feed/templates
mkdir feed/templates/feed
بعد ذلك ، قم بتحرير قالب في الدليل أعلاه ، وتغذية/قوالب/تغذية ، وأضف الكود لهذا المثال. دعونا نلقي نظرة على القالب لهذا المثال.
 
<!doctype HTML>
<html>
<body>
<legend>Feed</legend>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
</body>
</html>
 
هذا قالب بسيط للغاية. إنه يحدد فتح وإغلاق علامات HTML ، وعلامة نوع المستند ، وعلامة الجسم بعنوان أسطورة ، وعلامة كسر تضيف سطرًا صغيرًا عبر الشاشة ، وحلقة تجعل كل منشور في قائمة المنشورات كفقرة في الفقرة القالب. هذا كل ما يتطلبه الأمر لتقديم المنشورات ، ولكن لا يوجد شيء في قاعدة البيانات حتى الآن. دعنا ننشئ بعضًا مع القشرة. يمكننا تشغيل القشرة باستخدام manage.py

python manage.py shell
الآن ، دعنا نستورد نموذج منشورنا

from feed.models import Post
بعد ذلك ، سنقوم بإنشاء منشور بسيط مع سلسلة ونخرج من القشرة. يمكن أن تكون السلسلة أي شيء ، طالما أنه نص صالح.

Post.objects.create(text='hello world')
exit()
أخيرًا ، سنحتاج إلى إضافة نمط عنوان URL إلى خلاصتنا. نظرًا لأن تطبيق التغذية الخاص بنا سيستخدم عناوين URL متعددة ونريد الاحتفاظ بأحجام الملفات الصغيرة ، فلنقوم بإنشاء عنوان urls.py محلي في تطبيق التغذية الخاص بنا يبدو:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.feed, name='feed'),
]
سنحتاج أيضًا إلى تحرير urls.py في التطبيق الأساسي ، كل ما قررنا أن نسميه ، كان هذا هو الدليل الأول الذي أنشأناه. تحرير التطبيق/app.py وأضف ما يلي إلى أنماط عنوان URL

from django.urls import include # في الأعلى

urlpatterns = [
    # ... الرمز السابق هنا
    path('feed/', include(('feed.urls'), namespace='feed')),
]
الآن ، عندما نقوم بتشغيل الخادم باستخدام Python Manage.py Runserver ، سنرى الصفحة التي أنشأناها لأن لدينا النموذج والعرض والقالب وكذلك نمط عنوان URL ، إلى جانب العناصر الموجودة في قاعدة البيانات. بعد ذلك ، دعنا ننفذ النموذج الذي أنشأناه ويبدأ في إنشاء مشاركاتنا الخاصة. ولكن قبل أن نكتب الكثير من التعليمات البرمجية ، دعنا نقوم بعمل نسخة احتياطية باستخدام البرنامج النصي الذي كتبناه سابقًا ، نسخة احتياطية. قم بتشغيل هذا البرنامج النصي في القشرة ، وانتظر بضع لحظات ، وسيتم نسخ جميع الكود إلى مستودع GIT الخاص بنا.

backup
تنفيذ النموذج بسيط نسبيا. سنقوم باستيراد نموذجنا ، وإضافة معالج طلب نشر إلى العرض ، وحفظ المنشور في قاعدة البيانات قبل إعادة توجيه العرض نفسه. يمكننا استخدام وظيفة إعادة التوجيه التي قمنا باستيرادها بالفعل ، ودالة أخرى تسمى العكس للحصول على عنوان URL لنمط العرض. سنقوم بالاستعلام عن هذا باستخدام سلسلة "التغذية: التغذية" لأن مساحة اسم النمط المضمّن هي تغذية ، ويسمى العرض أيضًا التغذية.

from feed.forms import PostForm

def feed(request):
    posts = Post.objects.all() # الاستعلام عن جميع المنشورات في قاعدة البيانات حتى الآن
    if request.method == 'POST': # التعامل مع طلب النشر
        form = PostForm(request.POST) # قم بإنشاء مثيل للنموذج وحفظ البيانات إليه
        if form.is_valid(): # التحقق من صحة النموذج
            form.save() # حفظ الكائن الجديد
        return redirect(reverse('feed:feed')) # أعد التوجيه إلى عنوان URL نفسه مع طلب الحصول على
    return render(request, 'feed/feed.html', {
        'form': PostForm(), # تأكد من تمرير النموذج إلى السياق حتى نتمكن من تقديمه.
        'posts': posts,
    })
الآن ، سنحتاج إلى تحديث القالب لحساب النموذج الجديد. يمكننا القيام بذلك باستخدام
علامة في HTML وتقديم النموذج في قالب HTML مع زر إرسال. سنحتاج أيضًا إلى رمز CSRF ، وهو رمز يمنع المواقع الخارجية من النشر إلى النموذج دون تحميل الصفحة أولاً.
 
<!doctype HTML>
<html>
<body>
<legend>Feed</legend>
<form method=”POST”>
{% csrf_token %}
{{ form }}
<button type=”submit”>New Post</button>
</form>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
</body>
</html>
 
دعونا نقسم هذا. هناك فئة نموذجية جديدة ، رمز ، النموذج نفسه ، وزر إرسال. بسيط للغاية ، ولكن عندما نلقي نظرة عليه ، قد نرغب في جعلها تبدو أفضل. إنه يعمل ، يمكننا نشر منشورات جديدة مع النموذج ويتم حفظها الآن في قاعدة البيانات. هناك بعض الأشياء التي تحدث هنا. نستخدم علامات HTML لإعلان أن المستند هو مستند HTML ، نستخدم علامة قالب ({٪ ... ٪}) لتقديم الرمز المميز للنموذج ، وآخر ، {{...}} لتقديم النموذج. لدينا أيضًا حلقة لتقديم النص باستخدام علامات الكتلة وعلامة قالب. تعد علامات الحظر مهمة حقًا لأننا نستطيع تحديد كيفية تقديم أقسام القالب معها ، وعلامات القالب هي أساس كيفية وضع المتغيرات في الكود لدينا. الآن نحتاج إلى جعل تطبيقنا يبدو أفضل ، لأنه يبدو الآن أساسيًا. يمكننا القيام بذلك باستخدام CSS ، إما مضمّن ، أو في الفصول المرتبطة بكل كائن في المستند. CSS لطيف حقًا لأنه يخبر كل شيء على الصفحة كيف ينبغي أن تبدو ،ويمكن أن تجعلها تبدو جيدة حقًا. هناك عدد قليل من المكتبات التي يمكنها القيام بذلك ، لكن ذهابي الشخصي هو bootstrap. يمكن تنزيل bootstrap من موقعه على الويب ،getBootstrap.com/. بمجرد الوصول إلى هناك ، اضغط على الزر لقراءة مستندات التثبيت ، ونسخ الرمز من قسم VIA VIA عبر CDN. ستحتاج إلى هذا الرمز في الجزء العلوي من مستند HTML الخاص بك ، في علامة تسمى Head. أيضًا ، دعنا نمضي قدمًا وننشئ قالبًا أساسيًا حتى لا نحتاج إلى إعادة إنشاء هذه الروابط في كل قالب. قم بعمل دليل جديد يسمى قوالب مع قوالب MKDIR ، ثم تحرير القوالب/base.html. يجب أن يبدو هكذا:
 
<!doctype HTML>
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>
 
تأكد من نسخ ملفات CSS و JavaScript ، وملفات .CSS و .JS ، لأننا سنحتاج إلى JavaScript لجعل موقعنا أكثر وظيفية في المستقبل. الآن ، دعنا نعود إلى قذيفة باش وندير أمرًا سريعًا. تذكر أنه إذا كنت بحاجة إلى الوصول إلى البيئة الافتراضية ، فاكتب مصدر VenV/Bin/Activate. سيتيح لك ذلك تثبيت حزم Python محليًا بطريقة تتيح لـ Django الوصول إليها. لإعطاء أشكالنا التي تم إنشاؤها بواسطة دروس Bootstrap Django ، سنستخدم حزمة Python تسمى Forms Crispy. يمكننا تنزيل هذا مع الأمر التالي

pip install django-crispy-forms
بمجرد تثبيت هذا ، أضفه إلى الإعدادات.

INSTALLED_APPS = [
    # ... الرمز السابق هنا
    'crispy_forms',
]
الآن ، مرة أخرى في قالب التغذية لدينا ، يمكننا إزالة بعض الأشياء. دعنا نزيل بداية ونهاية المستند واستبدلها بالميراث من قالبنا الأساسي ، باستخدام تمديد وتعريف الكتلة. أيضًا ، سنضيف استيراد مرشح قالب مع التحميل ومرشح قالب إلى النموذج. أخيرًا ، دعنا نضيف فئة bootstrap إلى الزر الموجود في النموذج لجعله يشبه زرًا. يجب أن يبدو هكذا:
 
{% extends 'base.html' %}
{% block body %}
{% load crispy_forms_tags %}
<form method=”POST”>
{% csrf_token %}
{{ form|crispy }}
<button type=”submit” class=”btn btn-outline-primary”>New Post</button>
</form>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
{% endblock %}
 
جميل! هذا جزء كبير من التعليمات البرمجية بالفعل. بعد ذلك ، يجب أن نختبرها والتأكد من أننا نستطيع أن نرى أن كل شيء يبدو لطيفًا ، كما التأكد من أن كل شيء يعمل بشكل صحيح. قم بتشغيل الخادم وفقًا للتعليمات السابقة وتأكد من أن الموقع يبدو ويعمل بشكل جيد. عمل رائع! أنت مستعد للانتقال إلى الخطوة التالية ، والتي سنضيف فيها وظائف تسجيل الدخول إلى المستخدمين باستخدام عناوين URL والنماذج والمشاهدات والقوالب المماثلة. يعد القالب الأساسي مهمًا ، وسنواصل تعديله وإجراء تغييرات حسب الحاجة ، ولكن الآن دعونا نركز على جعل موقعنا أكثر أمانًا ، من خلال تمكين المستخدمين من تسجيل الدخول باستخدام اسم مستخدم ورمز مرور ، وفي النهاية معلومات أكثر أهمية سيساعد في الحفاظ على آمنة التطبيق الخاص بك والوصول إلى حسابك الخاص فقط من قبلك. للقيام بذلك ، سنحتاج إلى استخدام نموذج المستخدم المدمج في Django. نموذج المستخدم هو نموذج قاعدة بيانات ، مثل منشورنا ، يمكن تقديمه لتسجيل المستخدم في موقع الويب. في المستقبل ، قبل أن ننشر الموقع على الإنترنت ، سنقومقم بتوسيع هذا النموذج مع نماذج أخرى يعزى إليها ، وبناء تدابير أمنية إضافية لتسجيل الدخول المقاوم للتأثير. سنبدأ باستخدام بعض نماذج تسجيل الدخول المضمنة التي يوفرها Django. أولاً ، دعنا ننشئ تطبيقًا جديدًا سنستخدمه لتقديم القوالب وطلبات العرض لصفحة تسجيل الدخول الأساسية. سنقوم أيضًا بإنشاء تطبيقات أخرى لتمثيل تحديات تسجيل الدخول المستمرة من أجل تأمين التطبيق ، بما في ذلك pincode ، والتعرف على الوجه ، والاتصال المجال القريب ، والأجهزة الخارجية ، ومصادقة العوامل المتعددة ، والتعرف على بصمات الأصابع. تحدثنا بالفعل عن بدء تطبيق. من دليلنا ، داخل البيئة الافتراضية ، تم Pass Manage.py هذه

python manage.py startapp users
الآن ، يجب أن يكون لدينا دليل للتطبيق الجديد. لنبدأ بإنشاء طريقة عرض في هذا الدليل يتوافق مع تسجيل الدخول إلى المستخدم. قامت Django بإنشاء طرق عرض لتسجيلات تسجيل الدخول للمستخدمين ، ولكنها لن تكون مناسبة لنا لأننا بحاجة إلى عرض مخصص ، والذي يفضل القيام به مع تعريف. في هذا العرض ، سنبدأ من خلال التحقق من طلب نشر ، ومرضل. في المستخدمين/views.py ، أضف الرمز التالي

from django.shortcuts import render, redirect
from django.urls import reverse
from django.contrib.auth.forms import AuthenticationForm, SetPasswordForm
from django.contrib.auth import authenticate, logout
from django.contrib.auth import login as auth_login
from django.contrib import messages

def login(request):
    if request.method == “POST”:
        username = request.POST['username'] # احصل على اسم المستخدم وكلمة المرور من طلب النشر
        password = request.POST['password'] # مصادقة المستخدم
        user = authenticate(username=username, password=password)
        if user:
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
            messages.success(request, 'Your password was accepted. Please continue')
            return redirect(reverse('feed:feed'))
        else: messages.warning(request, 'Username or password incorrect. Please try again')
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
هذا هو كل ما تحتاجه لعرض تسجيل الدخول الأساسي. الآن ، دعنا ننشئ نموذجًا للعرض من خلال توسيع القالب الأساسي. سنبدأ بإنشاء دليل جديد للقوالب في مجلد المستخدمين.

mkdir users/templates
mkdir users/templates/users
الآن ، يجب أن نكون قادرين على تحرير المستخدمين/القوالب/المستخدمين/login.html. بينما نحن في ذلك ، سنقوم بإنشاء قالب للسماح للمستخدم بالتسجيل أيضًا.

nano users/templates/users/login.html
الآن ، في القالب ،
 
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form method="POST">
    {% csrf_token %}
    <fieldset class="form-group">
        <legend class="border-bottom mb-4 break">Log In</legend>
        {{ form|crispy }}
    </fieldset>
    <div class="form-group">
        <button class="btn btn-outline-info" type="submit">Login</button>
    </div>
</form>
{% endblock %}
 
هذه هي أساسيات قالب تسجيل الدخول. إنه حقًا مثل القالب الآخر في الهيكل ، لكنه يبدو مختلفًا بعض الشيء عند تقديمه. يمكننا نسخ هذا الرمز لإنشاء قالب آخر مشابه جدًا يسمى Record.html ، حيث سنقوم بتغيير الصياغة ونستخدم نموذجًا جديدًا نقوم ببنائه. لنجعل القالب أولاً. تحرير المستخدمين/القوالب/المستخدمين/register.html وأضف الكود التالي:
 
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form method="POST">
    {% csrf_token %}
    <fieldset class="form-group">
        <legend class="border-bottom mb-4 break">Create an account</legend>
        {{ form|crispy }}
    </fieldset>
    <div class="form-group">
        <button class="btn btn-outline-info" type="submit">Register</button>
    </div>
</form>
{% endblock %}
 
الآن ، دعنا نبني نموذجًا لتسجيل المستخدم الخاص بنا ونعود إلى المشاهدات قبل ترقية تسجيلات تسجيل الدخول الخاصة بنا باستخدام نموذج. سنجعل هذا النموذج أساسيًا للبدء به ، ولكن ندمج المزيد من التفاصيل وميزات الأمان مثل الاتفاقيات و Captcha في المستقبل. قم بتحرير النماذج مع مستخدمي/forms.py nano ، وأضف الكود التالي.

from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm

class UserRegisterForm(UserCreationForm):
    email = forms.EmailField()

    class Meta:
        model = User
        fields = ['username', 'email', 'password1', 'password2']
لذلك لدينا شكل آخر هنا ، والذي يعمل ببساطة إلى حد ما. إنه نموذج تسجيل مستخدم باسم المستخدم والبريد الإلكتروني وكلمة المرور ، بالإضافة إلى حقل تأكيد كلمة المرور. لاحظ أن هذا النموذج لا يمد فئة الأشكال العادية. يتم تعريف حقل واحد تمامًا ، ويحدد الفئة التعريف النموذج الذي يتوافقه النموذج مع بقية المعلومات التي سيتم كتابتها إلى النموذج. معظم هذا موجود بالفعل في Django المدمج في UserCreationForm ، لذلك سوف نستخدم ذلك كأساس للفئة (تم تمريره في قوسين). بعد ذلك ، سنقوم بفحص العرض لتسجيل مستخدم ، والآن بعد أن أصبح لدينا نموذج وقالب. هذا هو modelform ، تماما مثل واحد في عرض المنشور الجديد. تحرير المستخدمين/views.py وأضف الكود التالي:

# ... كميات
from .forms import UserRegisterForm

def register(request):
    if request.method == “POST”:
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            user = form.save()
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
هذا كل ما نحتاجه للحصول على مستخدم مسجل ، ولكن يجب أن يكون لدينا المزيد من المعلومات. نريد أن نعرف الوقت الذي سجل فيه المستخدم ، والوقت الذي كان عليه آخر مرة على الموقع ، وبعض المعلومات عنها ، مثل السيرة الذاتية ، والمنطقة الزمنية ، وما إلى ذلك أيضًا ، سنحتاج إلى تحديث نموذج التغذية لدينا ، النشر ، لحساب المستخدم النموذج والمنشورات السمة لكل مستخدم. من أجل القيام بذلك ، سنقوم بتحديث النماذج. لنبدأ بتحرير نموذج التغذية. يجب أن يبدو هكذا الآن:

from django.db import models # ... كميات
from django.contrib.auth.models import User

class Post(models.Model):
    id = models.AutoField(primary_key=True)
    author = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name='posts') # أضف في هذا الخط
    text = models.TextField(default='')
انتبه إلى السطر الثاني الذي تمت إضافته إلى الملف. هذا مفتاح أجنبي ، والذي يعزو كل منشور إلى مستخدم واحد لكل منشور ، حتى نتمكن من التأكد من أن نقوم بحفظ المنشورات على أساس المستخدم لكل مستخدم ولا يمكن إجراء أي منشور دون أن يعزى ذلك إلى مستخدم. نحن نحدد هذا المفتاح الأجنبي مع الفصل الذي يمثله ، وسيطة حذف لضمان حذف المنشورات مع المستخدمين ، والوسائط الخالية والفارغة للتأكد من أننا قادرون على إزالة المستخدم إذا لزم تم إنشاؤه ، واسم ذي صلة ، يمكننا استخدامه للإشارة إلى كائنات البريد التي ينشئها المستخدم. هذا الاسم المرتبط ، على عكس Post.Author ، مؤلف المنشور ، يعطينا المستخدم الذي نشر المنشور نفسه. يمكننا الآن الحصول على المشاركات التي يقوم بها المستخدم عن طريق تشغيل user.posts.all () ، أو uplor.posts.all (). الآن ، لنجعل تسجيلات تسجيلاتنا أكثر مرونة. يمكننا بالفعل أن نجعل موقعنا أقل عرضة للتخفيف من خلال الحد من عدد المرات التي سنسمح بها لتسجيل الدخول إلىالموقع ، هذا سهل للغاية. لنبدأ أيضًا في تخزين بعض المعلومات حول كل مستخدم من قبل مع استمرارنا في تطوير تطبيقنا. تحرير المستخدمين/models.py ، أضف ما يلي

from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True, related_name='profile')
    account_created = models.DateTimeField(default=timezone.now)
    last_seen = models.DateTimeField(default=timezone.now)
    can_login = models.DateTimeField(default=timezone.now)
    preferred_name = models.CharField(max_length=20,default='', null=True, blank=True)
    bio = models.TextField(blank=True, default='')
لاحظ أن هذا النموذج يشبه إلى حد ما نموذج البريد. لدينا استيراد إضافي ، TimeZone ، والذي سيسمح لنا بتعيين الإعدادات الافتراضية على حقول DateTime ، ولدينا أيضًا حرفًا و Textfield مثل المنشور. يساعدنا استخدام كل هذه الطوابع الزمنية على تأمين الموقع وفهم استخدامه ، ودعنا نضع معلومات حول كل مستخدم أو مؤلف على الموقع الإلكتروني. يجب أن يكون OneToOnefield هو الاعتبار البسيط الوحيد ، فهو يتصرف تمامًا مثل المقدمة ولكن مع واحد فقط لكل نموذج لاحق. وبهذه الطريقة ، يكون للمستخدم ملف تعريف واحد فقط ، في حين أنه قد يكون لديه العديد من المنشورات. الآن ، دعنا نحسن تسجيلات تسجيل الدخول وتسجيل مشاهداتنا لحساب ملف التعريف. أولاً ، قم بتحرير المستخدمين/views.py والتركيز على عرض التسجيل:

# ... كميات
from .forms import UserRegisterForm

def register(request):
    if request.method == “POST”:
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            user = form.save()
            Profile.objects.create(user=user) # تأكد من إضافة هذا السطر ، لإنشاء ملف تعريف للمستخدم
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
هذا ببساطة ينشئ ملف تعريف للمستخدم ، دون ملء أي من المعلومات. الآن ، نريد التأكد من أنه لا يمكن تسجيل حساب المستخدم في كثير من الأحيان ، أو على الأقل لا يمكن تجربة كلمات المرور في كثير من الأحيان ، لذلك دعنا نقوم بتحديث عرض تسجيل الدخول.

# ... الواردات
from .models import Profile
from django.utils import timezone
import datetime

def login(request):
    if request.method == “POST”:
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(username=username, password=password)
        if user and user.profile.can_login < timezone.now(): # لاحظ أننا الآن نتحقق مما إذا كان بإمكان المستخدم تسجيل الدخول
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
            messages.success(request, 'Your password was accepted. Please continue.')
            return redirect(reverse('feed:feed'))
        else: # إذا لم يكن تسجيل الدخول ناجحًا ،
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # هذا هو الجزء الذي نقوم فيه بتحديث ملف تعريف المستخدمين
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # لذلك لا يمكنهم تسجيل الدخول مرة أخرى لبضع ثوان
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
هذا هو الأساس الأساسي للأمن. تأكد من أن الموقع ليس عرضة لشخص ما ببساطة يحاول كل مجموعة كلمة مرور ممكن ، أو حتى عدد قليل منها في نفس الوقت. لن يكون هذا الأمر محبطًا للمستخدم العادي الذي يعرف رمز المرور الخاص بهم ويسجل الدخول على عدد قليل من الأجهزة ، لكنه سيبقي العديد من روبوتات التصيد خارج التطبيق. لاحظ أننا أضفنا عبارة if مع متغير ، Can_login ، يجب أن يكون وقتًا في الماضي ، ونقوم بتحديثه مع كل تسجيل الدخول غير الناجح باستخدام اسم المستخدم نفسه. وبهذه الطريقة ، لن يتمكن المستخدم الضار من تخمين كلمة مرور في أي مكان قريب. يمكن تحديث عدد الثواني في DateTime.Timedelta () أيضًا ، وسيكون الموقع أكثر مرونة ولكنه أقل قابلية للاستخدام مع ثوانٍ أكثر. أوصي 15 للبدء مع. تذكر ، لقد قمنا ببناء نص احتياطي لإنقاذ عملنا ، لذلك دعونا نتقدم وندعم ما لدينا حتى الآن للتأكد من حفظ كل شيء. قم بتشغيل الأمر:

sudo backup
مرة أخرى ، سيوفر هذا عملك حتى الآن. أوصي بتشغيل النسخ الاحتياطية المتكررة لإنقاذ عملك ، وقد ترغب حتى في تشغيل وظيفة النسخ الاحتياطي تلقائيًا. يمكنك القيام بذلك باستخدام أداة UNIX تسمى CRON. لتفعيل هذه الأداة ، قم بتشغيل الأمر التالي وأدخل كلمة المرور الخاصة بك:

sudo crontab -e
إذا لم تكن قد حددت بالفعل الخيار 1 لـ Nano ، فيجب أن تكون محرر النصوص على دراية به بالفعل ، والتمرير إلى أسفل الملف باستخدام مفاتيح الأسهم. أضف السطر التالي:

0 * * * * sudo backup
يستخدم CRON الدقائق الدقيقة ، ساعة ، يوم من الشهر ، الشهر ، يوم من الأسبوع ، حيث يمثل A * أو رقم متى يتم تشغيل الأمر. باستخدام 0 للدقيقة و * لبقية الخيارات ، يمكننا تشغيل أمر في الدقيقة الأولى من كل ساعة في بداية الدقيقة. هذا يتيح لنا نسخ الكود تلقائيا. جميع وظائف Cron عند تنفيذها باستخدام Sudo Run كجذر ، لذلك لن نحتاج إلى كتابة كلمة مرور كل ساعة. لتسهيل دعم رمزنا دون استخدام كلمة مرور ، دعنا نقوم بتعطيل كلمة المرور لأمر النسخة الاحتياطية الخاصة بنا. سنفعل ذلك من خلال تنفيذ الأمر التالي وإدخال كلمة مرور:

sudo visudo
الآن ، دعنا ننتقل إلى أسفل الملف وأضف سطرًا آخر:

ALL ALL=NOPASSWD: /bin/backup
هذا يتيح لنا تشغيل الأمر "النسخ الاحتياطي" كأي مستخدم ، بدون كلمة مرور. من السهل تنسيق هذا الأمر ، فقط بادئة الخط مع "الكل = nopasswd:/bin/" وإنهاء الأمر ، على سبيل المثال/bin/backup ، الموجود في/usr/bin/. الآن ، لنبدأ العمل مع البريد الإلكتروني. البريد الإلكتروني مهم حقًا لمواقع الويب ، لأنها طريقة للحفاظ على موقع الويب أكثر أمانًا ، والتحقق من أن المستخدمين هم أشخاص حقيقيون ، وحتى منتجات أو خدمات السوق للعملاء. العديد من الأشخاص الذين يتكررون على الإنترنت يتحققون من بريدهم الإلكتروني يوميًا ، ويتلقون جميع أنواع البريد الإلكتروني للتسويق حول المنتجات والخدمات التي يهتمون بها. هناك بعض الخيارات عندما يتعلق الأمر بتمكين البريد الإلكتروني على موقع Django ، وترحب بك في الاختيار أيهما يعمل بشكل أفضل بالنسبة لك. أولاً ، يمكنك الدفع مقابل خدمة البريد الإلكتروني التي ستمكنك من إرسال بريد إلكتروني من مجالك وتتطلب الحد الأدنى من الرمز. هناك العديد من الخدمات التي تقدم هذا ، مثل Google Workspace و SendInblue و MailGun والمزيد. خلاف ذلك ، أنت خارج البناءخدمة البريد الإلكتروني الخاصة بك داخل الخادم الخاص بك من نقطة الصفر. أوصي بهذا الخيار ، على الرغم من أنه أكثر رمزًا وقد يتطلب استضافة خاصة. لن تكون قادرًا على بدء تشغيل خادم بريد من الكمبيوتر المنزلي على الأرجح ، لذلك دعنا نمضي قدماً ونفحص التكوين والرمز لإرسال بريد إلكتروني قبل أن نبدأ خادمًا في السحابة وإنشاء خادم البريد الخاص بنا. أولاً ، تحرير الإعدادات.

nano app/settings.py
حيث التطبيق هو اسم التطبيق الذي أنشأته مع StartApp. أضف الأسطر التالية:

SITE_NAME = 'Django App'

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'localhost'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_ADDRESS = username@server.com'
EMAIL_HOST_USER = 'username'
EMAIL_HOST_PASSWORD = config['EMAIL_HOST_PASSWORD']
DEFAULT_FROM_EMAIL = '{} <{}>'.format(SITE_NAME, EMAIL_HOST_USER)
تأكد من تغييرها عندما تكون مستعدًا لنشر تطبيقك ، سنقوم بإعادة النظر في ذلك لاحقًا. يجب أن يكون إعداد البريد الإلكتروني eMail_address هو البريد الإلكتروني الذي ترغب في إرساله منه ، ويجب تعيين كلمة المرور (eMail_Host_Password) على كلمة المرور التي تنشئها للخادم. أقوم بتحميل كلمة المرور من ملف التكوين لإبعادها عن الكود باستخدام المنطق التالي ، فوق هذه الأسطر في الإعدادات.

import os
import json
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
بعد ذلك ، قمت بإعداد ملف JSON مع config in /etc/config.json باستخدام nano على النحو التالي. لتحرير الملف:

sudo nano /etc/config.json
أضف الأسطر التالية:

{
	“EMAIL_HOST_PASSWORD”: “<some password here>”
}
سنستمر في تحرير ملف التكوين وإضافة جميع كلمات المرور والمفاتيح التي سنستخدمها في التطبيق. في الوقت الحالي ، دعنا ندرس بسرعة كيفية إرسال بريد إلكتروني باستخدام Python. أولاً ، دعنا ننشئ قالبًا للاطلاع على بريد إلكتروني للتحقق ، يمكننا إرساله إلى مستخدمينا ، ووضعه في دليل قوالب المستخدم. سيتم كتابة هذا القالب في HTML.

nano users/templates/users/verification_email.html
 
<h1>Django App - Verify Your Email</h1>
<p>Dear {{ user.username }},</p>
<p>To verify your email, please <a href="{{ base_url }}{% url 'users:activate' uidb64=uid token=token %}">click here</a>.</p>

<p>Alternatively, you can paste the following link in your browser's address bar:</p>
<p>{{ base_url }}{% url 'users:activate' uidb64=uid token=token %}</p>

<p>The link will expire in 30 minutes.</p>
<p>If you have not requested a verification email you can simply ignore this email.</p>
<p>See you there,</p>
<p>Daisy</p>
 
هذا البريد الإلكتروني بسيط إلى حد ما. يستغرق سياق المستخدم وعنوان URL الأساسي للموقع ومعرف المستخدم والرمز المميز المستخدم للتحقق من بريد إلكتروني المستخدم. تأكد من تحديد عنوان URL الأساسي في الإعدادات. اطلب قبل أن نكتب بعض رمز Python لتقديم القالب. المضي قدما وأضف الأسطر التالية إلى التطبيق/الإعدادات ، بالقرب من البداية.

SITE_NAME = 'Django App'
PROTOCOL = 'https'
DOMAIN = 'example.com'

BASE_URL = PROTOCOL + '://' + DOMAIN
في النهاية ، عندما يكون موقعك جاهزًا للإنترنت ونشره ، ستحتاج إلى تحديد نطاقك كاسم المجال الذي تشتريه لتمثيل الموقع. هذا هو الاسم الذي ستكتبه في Navbar للوصول إلى موقعك. في الوقت الحالي ، يمكنك ترك المجال فارغًا أو استخدام عنصر نائب. ستحتاج أيضًا إلى تغيير موقع site_name إلى اسم تريد إعطاء موقعك ، من اختيارك. قبل أن نرسل بريدًا إلكترونيًا ، دعنا ننشئ مولدًا رمزيًا حتى نتمكن من الحصول على رمز تنشيط الحساب الذي لا ينتهي صلاحيته أبدًا. يمكننا القيام بذلك عن طريق بناء واستيراد رمز تنشيط الحساب الذي يشبه ما يلي. تحرير الملف:

nano users/tokens.py
أضف الرمز التالي:

from django.contrib.auth.tokens import PasswordResetTokenGenerator
import six
class TokenGenerator(PasswordResetTokenGenerator):
    def _make_hash_value(self, user, timestamp):
        return (
            six.text_type(user.pk) + six.text_type(timestamp)
        )
account_activation_token = TokenGenerator()
unsubscribe_token = TokenGenerator()
يقوم هذا المولد الرمزي الأساسي بإنشاء رمز مميز يمكننا إرسال المستخدم في عنوان URL ويمكن للمستخدم استخدامه للتحقق من بريده الإلكتروني وتنشيط حسابه. بعد ذلك ، دعنا نرى كيفية إرسال بريد إلكتروني. باستخدام Nano ، تحرير المستخدمين/البريد الإلكتروني.

nano users/email.py
سيبدو إرسال بريد إلكتروني HTML التحقق من ذلك:

from django.contrib.auth import get_user_model
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.contrib.sites.shortcuts import get_current_site
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils.encoding import force_bytes
from django.core.mail import EmailMultiAlternatives
from django.shortcuts import render
from .tokens import account_activation_token
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.template import Template, Context
from django.conf import settings
import traceback

def send_verification_email(user):
    User = get_user_model()
    mail_subject = '[{}] Activate your account.'.format(settings.SITE_NAME)
    html_message = render_to_string('users/verification_email.html', {
        'user': user,
        'domain': settings.DOMAIN,
        'protocol': 'https',
        'uid': urlsafe_base64_encode(force_bytes(user.pk)),
        'token': account_activation_token.make_token(user),
    })
    send_html_email(user, mail_subject, html_message)
هذا بسيط إلى حد ما. نحن نستورد الوظائف التي نحتاجها لإرسال البريد الإلكتروني ، وتقديم البريد الإلكتروني باستخدام القوالب ، وإعداداتنا ، ثم نحدد البريد الإلكتروني باسم القالب ونرسله إلى المستخدم باستخدام وظيفة. ستلاحظ أننا لم نحدد الوظيفة لإرسال البريد ، send_html_email ، حتى الآن ، لذلك دعونا نكتب هذا أسفل الرمز الذي أضفناه بالفعل إلى المستخدمين/البريد الإلكتروني

def send_html_email(user, mail_subject, html_message):
    to_email = user.email
    username = user.username
    if to_email == '':
        return None
    unsub_link = settings.BASE_URL + user.profile.create_unsubscribe_link()
    html_message = html_message + "<p><a href=\"" + unsub_link +  "\" + title=\"Unsubscribe from " + settings.SITE_NAME + " emails\">Unsubscribe</a></p></body></html>"
    msg = EmailMultiAlternatives(mail_subject, strip_tags(html_message), settings.DEFAULT_FROM_EMAIL, [to_email], headers={'List-Unsubscribe' : '<' + unsub_link + '>'},)
    msg.attach_alternative(html_message, "text/html")
    profile = user.profile
    try:
        msg.send(fail_silently=False)
        if not profile.email_valid:
            profile.email_valid=True
            profile.save()
    except:
        profile.email_valid=False
        profile.save()
هذا أكثر تعقيدًا قليلاً ، ونحن لسنا مستعدين لتشغيل كل هذا الرمز حتى الآن. لاحظ أننا نحدد unsub_link ، الرابط الذي يمكن للمستخدم استخدامه لإلغاء الاشتراك من رسائل البريد الإلكتروني الخاصة بنا. هذا أمر مهم ، لأن المستخدمين سيحتاجون إلى أن يكونوا قادرين على إلغاء الاشتراك في رسائل البريد الإلكتروني الخاصة بنا ما لم يرغبوا في رؤيتها ، في أي وقت. نضيف أيضًا بديلًا نصًا لرسالةنا ، وهي رسالة HTML التي تم تجريدها من علامات HTML. أخيرًا ، نتحقق مما إذا كان البريد الإلكتروني المرسل ، وإذا لم يحدث ذلك ، فإننا نضع علامة في ملف تعريف المستخدم بأن بريده الإلكتروني غير صالح. دعنا نعود إلى نماذج المستخدم حتى نتمكن من جعل كل هذا يعمل. نحتاج إلى تحديد وظيفة لإنشاء رابط لإلغاء الاشتراك ، وتحديد حقل منطقي لتمييز أن البريد الإلكتروني للمستخدم غير صالح. أولاً ، أضف الواردات التالية إلى أعلى المستخدمين/النماذج

nano users/models.py

# ...
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from django.urls import reverse
بعد ذلك ، دعنا نضيف وظائف إلى نموذج المستخدم لجعل الرمز المميز والتحقق من الرمز المميز المستخدم لتنشيط البريد الإلكتروني ، وكذلك الحقل لحفظ ما إذا كان المستخدم يتلقى بريده بنجاح. في المستخدمين/النماذج مرة أخرى ، أضف الكود التالي إلى نهاية النموذج (رمز بادئة)

# ...
    email_valid = models.BooleanField(default=True)
    
    def make_token(self):
        return TimestampSigner().sign(self.user.username)

    def check_token(self, token):
        try:
            key = '%s:%s' % (self.user.username, token)
            TimestampSigner().unsign(key, max_age=60 * 60 * 24 * 30) # صالح لمدة 30 يومًا
        except (BadSignature, SignatureExpired):
            return False
        return True

    def create_unsubscribe_link(self):
        username, token = self.make_token().split(":", 1)
        return reverse('users:unsubscribe', kwargs={'username': username, 'token': token,})
هذا بسيط إلى حد ما ، نستخدم طابع زمني ، وهو أداة تشفير أساسية ، لإنشاء رمز مميز سينتهي بعد فترة زمنية معينة ، ونستخدم أيضًا وظيفة أخرى للتحقق مما إذا كانت صالحة. نستخدم هذه الرموز مرتين ، مرة واحدة للتحقق من البريد الإلكتروني ، ومرة ​​واحدة للحصول على رابط إلغاء الاشتراك. الآن بعد أن لدينا هذه ، فإن آخر العمل الذي سنحتاج إلى القيام به هو في الآراء. ضمن المستخدمين/views.py ، دعنا نضيف طرق عرض للتحقق من عنوان البريد الإلكتروني ، وإلغاء الاشتراك.

nano users/views.py
أولاً ، أضف الواردات التالية. رميت بضع إضافي حتى لا نضطر إلى استيراد المزيد من العناصر مرة أخرى لاحقًا.

from django.contrib.auth import logout
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.models import User
from django.utils.encoding import force_str
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
import json
import requests
import datetime, traceback
from django.contrib import messages
from .models import Profile
from django.utils import timezone
from django.views.decorators.cache import never_cache
from .email import send_verification_email # تأكد من استيراد وظيفة إرسال البريد الإلكتروني للتحقق
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.utils.decorators import method_decorator
from django.http import HttpResponseRedirect
from django.conf import settings
from django.utils import timezone
import datetime
import pytz
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_decode
from .tokens import account_activation_token
قد يكون لديك بالفعل بعض هذه الواردات ، لكن لا يؤلمني تكرارها. ستحتاج إلى استيراد وظيفة إرسال البريد الإلكتروني للتحقق ، بالإضافة إلى حساب _activation_token من user.tokens ، من بين واردات أخرى. الآن ، في أسفل الملف ، أضف الرمز التالي:

def unsubscribe(request, username, token):
    user = get_object_or_404(User, username=username)
    if((request.user.is_authenticated and request.user == user) or user.profile.check_token(token)):
        # إلغاء الاشتراك لهم
        profile = user.profile
        profile.subscribed = False
        profile.save()
        return render(request, 'users/unsubscribe.html')
    # خلاف ذلك إعادة توجيه صفحة تسجيل الدخول
    messages.warning(request,f'Your unsubscribe link has expired. Please log in to unsubscribe.')
    next_url = reverse('users:unsubscribe', kwargs={'username': username, 'token': token,})
    return HttpResponseRedirect('%s?next=%s' % (reverse('login'), next_url))

def activate(request, uidb64, token):
    try:
        uid = force_str(urlsafe_base64_decode(uidb64))
        user = User.objects.get(pk=uid)
    except(TypeError, ValueError, OverflowError, User.DoesNotExist):
        user = None
    ip = get_client_ip(request)
    if user is not None and account_activation_token.check_token(user, token):
        user.profile.email_verified = True
        user.profile.save()
        user.save()
# SendWelcomeEmail (طلب ، مستخدم)
        messages.success(request, f'Thanks for confirming your email! You can now log into your account, and a welcome email has been sent to you.')
        return redirect(user.profile.create_face_url())
    else:
        messages.success(request, f'Your activation link has expired. Please request a new activation link.')
        return redirect('verify:verify')

def resend_activation(request):
    if request.method == 'POST':
        form = ResendActivationEmailForm(request.POST)
        email = request.POST['email']
        try:
            user = User.objects.get(email=email)
            send_verification_email(user)
            messages.success(request,'Your verification email sent. Please click the link in your email to verify your account.')
            return redirect(reverse('verify:verify'))
        except:
            messages.warning(request,f'Your email is not correct. Please try again.')
    else:
        form = ResendActivationEmailForm()
    return render(request,'users/resend_activation.html',{'form': form, 'title': 'Resend Activation', 'small': True})
هذا هو الكثير من الكود. دعونا نقسمه. الوظيفة الأولى ، نظيفة وبسيطة ، تفلت من المستخدم من القائمة البريدية. تعمل الوظيفة الثانية على تنشيط بريدهم الإلكتروني ، وستلاحظ أنني أضفت وظيفة معلمة ، SendWelcomeEmail. اهلا وسهلا بكم لاستخدام قالب البريد الإلكتروني وتعريف الوظيفة لإرسال بريد إلكتروني ترحيب ، لم أفعل بعد. الوظيفة الأخيرة التي ألقيتها مهمة ، لأن رسائل البريد الإلكتروني للتنشيط تنتهي. لذلك ، سنحتاج إلى إعادة تقديم البريد الإلكتروني للتنشيط بعض الوقت. يمكننا استخدام نموذج أساسي لهذا الغرض ، والاتصال بالوظيفة لإرسال بريد إلكتروني التحقق. قبل القيام بذلك ، دعونا نتأكد من إرساله في المقام الأول ، عن طريق إضافة استدعاء وظيفة إلى عرض التسجيل. أضف هذا السطر قبل إعادة التوجيه مباشرة في عرض التسجيل ، سجل DEF ، في المستخدمين/views.py.

nano users/views.py

# ... (بعد) سجل DEF (طلب):
            send_verification_email(user)
# ... (قبل) إعادة توجيه (
لا تحتاج إلى إضافة الأسطر الأولى والأخيرة في مقتطف الرمز هذا ، فقط تأكد من أن طريقة عرض التسجيل يرسل البريد الإلكتروني للتحقق إلى المستخدم. يجب أن يبدو هكذا:

# ... كميات
from .forms import UserRegisterForm

def register(request):
    if request.method == “POST”:
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            user = form.save()
            send_verification_email(user) # تأكد من إضافة هذا الخط!
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
الآن ، سنحتاج إلى إضافة نموذج لإعادة إرسال بريد إلكتروني التنشيط. في المستخدمين/forms.py ، أضف النموذج التالي:

# ... (المبالغ)
class ResendActivationEmailForm(forms.Form):
    email = forms.EmailField(required=True)
سنحتاج أيضًا إلى قالب يتوافق مع نموذج تنشيط البريد الإلكتروني لإعادة الالتحاق. دعنا نضيف هذا القالب في. تحرير الملف:

nano users/templates/users/resend_activation.html
بعد ذلك ، أضف الكود التالي إلى الملف.

{% extends 'base.html' %}
{% block content %}
{% load crispy_forms_tags %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Resend activation email</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-secondary" type="submit">Resend activation email</button>
            </div>
        </form>
{% endblock %}
يا للعجب ، هذا كثير! الآن ، عندما نقوم بنشر الرمز على الخادم الخاص بنا ، سنكون قادرين على إرسال بريد إلكتروني HTML وتنشيط حسابات المستخدمين بنقرة في البريد الإلكتروني. قد نرغب أيضًا في إرسال بريد إلكتروني ترحيب بسيط ، لذلك دعونا نرى كيفية القيام بذلك. مرة أخرى في المستخدمين/البريد الإلكتروني ، أضف الرمز التالي:

def sendwelcomeemail(user):
    User = get_user_model()
    html = open('{}/users/welcome_email.html'.format(settings.BASE_DIR)).read()
    subject = 'Welcome to ' + settings.SITE_NAME + ', {{ username }}!'
    template = Template(html)
    subjtemplate = Template(subject)
    context = Context({'username': user.username, 'base_url': settings.BASE_URL, 'model_name': 'Daisy Holton, 'site_name': settings.SITE_NAME})
    renderedtemplate = template.render(context)
    subjcontext = Context({'username': user.username})
    subjrenderedtemplate = subjtemplate.render(subjcontext)
    send_html_email(user, subjrenderedtemplate, renderedtemplate)
أيضًا ، سنحتاج إلى قالب لتقديم كل هذه المعلومات. على موقع الويب الخاص بي ، يشبه القالب أدناه ، لكنك نرحب بك لتنسيقه كما تريد.
 
<html>
<body>
<h3>Welcome to {{ site_name }}</h3>
<p>Hello {{ username }},</p>
<p>We are happy to see you here! Thank you for joining {{ site_name }} and being a part of the fun. To get started, here are a few things you can do after you verify your identity.</p>
<ol>
    <li><a href="{{ base_url }}/" title="Use the app">Use the app</a>. This is the main page of {{ site_name }}</li>
    <li><a href="{{ base_url }}/feed/profile/Clementine/" title="See my profile">Visit my private {{ site_name }} profile</a>. This is a page for anyone wanting to get to know me.</li>
    <li><a href="{{ base_url }}/feed/profiles/" title="See all profiles currently on the site">More profiles</a>. You can find these people on the site, and see their content.</li>
    <li><a href="{{ base_url }}/feed/all/" title="See everything on {{ site_name }}">See all posts here</a>. This is the private front page of {{ site_name }}.</li>
</ol>
<p>There is even more on the site, so feel free to visit and see what you find. You can share the site with any of the social buttons on each page. I hope you enjoy your time with {{ site_name }}! Thanks for being here.</p>
<p>With much love,</p>
<p>{{ model_name }}</p>
<a href="{{ base_url }}" title="{{ site_name }}">{{ base_url }}</a>
 
لاحظ أنه لا يوجد لدينا علامات إغلاق أو علامات HTML ، لأننا نضيفها عندما نضيف رابط HTML Unsubscribe. هذه مهمة ، لكننا لا نريد تحديدها مرتين. إذن ماذا بعد؟ لقد قطعنا شوطا طويلا. حقًا ، يجب أن نكون مستعدين لنشر الموقع على خادم. يمكننا إضافة decorator login_required وجعل وجهات نظرنا آمنة ، واتخاذ تسجيلات المستخدم ، وإرسال بريد إلكتروني متوافقة ، ومعلومات ذاكرة التخزين المؤقت ، وهو أساس ما يحتاج موقع الويب للاستمرار فيه. سنضيف بعض الميزات المفيدة ، ثم قم ببناء أساس لنشر الكود لدينا على خادم بعيد ، وإعداد خادم البريد ، وتكوين المجال ، والمرشحات لجعل موقعنا آمنًا ومناسبًا. سنحتاج أيضًا إلى عرض إعادة تعيين كلمة المرور ، لذلك دعونا نضيف ذلك بسرعة. يتم كسر عرض إعادة تعيين كلمة المرور المدمجة في Django في بعض الوظائف ، لكننا سننظر في كيفية كتابة عرضنا الخاص ، وقالب البريد الإلكتروني ، والنماذج ، وأنماط URL. إليك ما يبدو عليه العرض ، في المستخدمين/views.py

# ... المبالغ
from django.contrib.auth.tokens import default_token_generator
from django.contrib.auth.forms import SetPasswordForm
from django.utils.http import urlsafe_base64_decode

def password_reset(request, uidb64, token):
    user = get_object_or_404(User, id=urlsafe_base64_decode(uidb64))
    if request.method == 'POST':
        form = SetPasswordForm(user, request.POST)
        if form.is_valid() and default_token_generator.check_token(user, token):
            form.save()
            messages.success(request, 'Your password has been reset.')
        elif not form.is_valid():
            messages.warning(request, 'Your passwords do not match, or do not meet the requirements. Please try again.')
            return redirect(request.path)
        else:
            messages.warning(request, 'Your password reset link has expired. Please create a new one.')
        return redirect(reverse('users:login'))
    return render(request, 'users/password_reset_confirm.html', {
        'title': 'Reset your Password',
        'form': SetPasswordForm(user)
هذا النموذج مدمج في Django ، لكننا سنحتاج إلى قالب لتأكيد إعادة تعيين كلمة المرور والمستخدمين/القوالب/المستخدمين/password_reset_confirm.html
 
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Reset Password</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-info" type="submit">Reset Password</button>
            </div>
        </form>
{% endblock content %}
 
لدينا أيضًا قالب لإرسال بريد إلكتروني لإعادة تعيين كلمة المرور ، مع نموذج بسيط ، في المستخدمين/القوالب/المستخدمين/password_reset.html
 
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Reset Password</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-info" type="submit">Request Password Reset</button>
            </div>
        </form>
{% endblock content %}
 
قالب البريد الإلكتروني نفسه بسيط ، إنه ملف HTML أساسي يعرض رابطًا لإعادة ضبط كلمة المرور ، في المستخدمين/القوالب/المستخدمين/password_reset_email.html. سيقوم Django تلقائيًا بتفسير هذا الملف.
 
<h1>Uglek - Reset Your Password</h1>
<p>Hello,</p>
<p>To reset your password, please <a href="https:/uglek.com{% url 'password_reset_confirm' uidb64=uid token=token %}">click here</a>.</p>
<p>Alternatively, you can paste the following link into your browser:</p>
<p>https://uglek.com{% url 'password_reset_confirm' uidb64=uid token=token %}</p>
<p>If you have not requested a password reset you can simply ignore this email.</p>
<p>Thanks for joining us,</p>
<p>Daisy</p>
 
سنحتاج أيضًا إلى قوالب أخرى. الأول هو تأكيد إرسال البريد الإلكتروني. وجهات النظر الخاصة بها موجودة بالفعل في Django ، لذلك نحتاج فقط إلى معالجتها في urls.py. يقع هذا القالب في المستخدمين/القوالب/المستخدمين/password_reset_done.html
 
{% extends 'base.html' %}
{% block content %}
  <div class="media-body">
    <div class="alert alert-info">
        An email has been sent with instructions to reset your password.
    </div>
  </div>
{% endblock content %}
 
وأخيرًا ، للتأكيد على أن إعادة تعيين كلمة المرور قد اكتملت ، المستخدمون/القوالب/المستخدمين/password_reset_complete.html
 
{% extends 'base.html' %}
{% block content %}
 <div class="media-body">
    <div class="alert alert-info">
        Your password has been set.
    </div>
    <a href="{% url 'users:login' %}">Sign In Here</a>
  </div>
{% endblock content %}
 
الآن ، نحتاج إلى أنماط URL لهذه المشاهدات. في المستخدمين/urls.py ، أضف أنماط URL التالية:

urlpatterns = [
    # ... عناوين URL السابقة هنا
    path('password-reset/',
         auth_views.PasswordResetView.as_view(
             template_name='users/password_reset.html',
             html_email_template_name='users/password_reset_html_email.html'
         ),
         name='password_reset'),
    path('password-reset/done/',
         auth_views.PasswordResetDoneView.as_view(
             template_name='users/password_reset_done.html'
         ),
         name='password_reset_done'),
    path('password-reset-confirm/<uidb64>/<token>/',
         auth_views.PasswordResetConfirmView.as_view(
             template_name='users/password_reset_confirm.html'
         ),
         name='password_reset_confirm'),
    path('password-reset-complete/',
         auth_views.PasswordResetCompleteView.as_view(
             template_name='users/password_reset_complete.html'
         ),
         name='password_reset_complete'),
]
أربعة قوالب ، هذا كثير! ولكن الآن يمكننا أن نكون متأكدين من إعادة تعيين كلمة مرور المستخدم في أي وقت نحتاج إليه ، كل ذلك من متصفح الويب. أنا أفهم أن هذا هو الكثير من التعليمات البرمجية. إذا كان يبدو قليلاً فوق رأسك ، فلا بأس. سوف تتحسن ، سوف يتحسن فهمك ، وسوف تصبح أكثر كفاءة مع التعليمات البرمجية في وقت قريب جدا. إذا كنت ضائعًا تمامًا ، أوصي بالعودة إلى هذا البرنامج لاحقًا بعد العمل على دورة تدريبية ذاتية تعلّم إلى Code Course Online. عادة ما تكون مجانية للبدء ، وسوف توجهك عبر كل ما تحتاجه لتكون ناجحًا عندما تعود إلى هذا المشروع. إذا كنت تشعر أنك مستعد للمتابعة ، تابع القراءة ، بعد ذلك ، سنقوم بتغطية نشر الكود الخاص بك على خادم بعيد وإعداد خادم بريد ، بالإضافة إلى أتمتة نشرك باستخدام Bash حتى تتمكن دائمًا من إعداد مشروع جديد مع بعض الأوامر البسيطة. آخر شيء نحتاج إلى القيام به قبل النشر في خادم بعيد هو جعل موقعنا أكثر أمانًا. سوفلاحظ أن عرض تسجيل الدخول يأخذ فقط اسم المستخدم وكلمة المرور ، وليس هناك مصادقة متعددة العوامل أو رمز لمرة واحدة. هذا حل سهل ، ومع نفس الرمز ، يمكننا جعل موقعنا يرسل رسائل نصية وحتى نستجيب للرسائل النصية المرسلة إلى الخادم. للبدء ، سنعود إلى نماذج المستخدم وإضافة علامة زمنية تمثل كل تسجيل الدخول. سنضيف أيضًا معرفًا فريدًا ودورًا إلى نموذج المستخدم الذي سيتم استخدامه لإضافة أمان إضافي إلى تسجيل الدخول لدينا. تحرير نماذج المستخدم والمستخدمين/النماذج

from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
# تأكد من استيراد موقع Uuid و Timestamp Signer ومولد URL (عكس)
import uuid
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from django.urls import reverse

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True, related_name='profile')
    account_created = models.DateTimeField(default=timezone.now)
    last_seen = models.DateTimeField(default=timezone.now)
    can_login = models.DateTimeField(default=timezone.now)
    preferred_name = models.CharField(max_length=20,default='', null=True, blank=True)
    bio = models.TextField(blank=True, default='')
    # أضف هذا الرمز هنا
    uid = models.CharField(max_length=32, default=uuid.uuid4, null=True, blank=True)
    mfa_enabled = models.BooleanField(default=False)
    enable_mfa = models.BooleanField(default=False)
    phone_number = models.CharField(default='', null=True, blank=True, max_length=15)
    verification_code = models.CharField(default='', null=True, blank=True, max_length=15)
    verification_code_length = models.IntegerField(default=6)
    mfa_code_expires = models.DateTimeField(default=timezone.now)
    mfa_attempts = models.IntegerField(default=0)

    def make_auth_token(self):
        return TimestampSigner().sign(self.uid)

    # وأضف هذه الوظيفة
    def create_auth_url(self):
        username, token = self.make_auth_token().split(":", 1)
        return reverse('users:mfa', kwargs={'username': username, 'token': token,})

    def check_auth_token(self, token):
        try:
            key = '%s:%s' % (self.uid, token)
            TimestampSigner().unsign(key, max_age=60 * settings.AUTH_VALID_MINUTES) # صالح لمدة 3 دقائق
        except (BadSignature, SignatureExpired):
            return False
        return True
تأكد من أن المستخدمين/النماذج الخاصة بك يبدو هكذا ، إلى جانب التعليقات (رمز على السطور مع #). كسر هذا ، الأمر بسيط. لدينا عدد قليل من الواردات ، وهو طابع زمني ، وهو أداة تشفير يمكن أن تنشئ رمزًا آمنًا والتحقق منه للتأكد من أنه صحيح ، ولم يتم استخدامه إلا مرة واحدة ، وليس أكبر من عدد معين من الثواني. نستخدم أيضًا UUID ، وهو معرف فريد يحدد مستخدمنا في توقيع الرمز المميز ، وفي عنوان URL حيث يتم إرسال الرمز المميز إلى المستخدم. سنستخدم هذا التشفير الأساسي لبناء عرض مصادقة لعامل. قبل أن نفعل أي شيء آخر ، دعنا ندير الترحيل بحيث يتم تحديث نماذج المستخدم لدينا. في الدليل مع manage.py ، قم بتشغيل الأوامر التالية لصنع وإكمال الترحيل.

source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
هذا أمر مهم لأنه في كل مرة نقوم بإجراء تغييرات على النماذج ، سنحتاج إلى إنشاء الجداول وتحديث قاعدة البيانات مع الافتراضات قبل أن نتمكن من استخدام النماذج بالفعل. بعد ذلك ، دعنا نرتدي عرض تسجيل الدخول الخاص بنا لإعادة توجيه إلى عرض مصادقة ثانوي. في المستخدمين/views.py ، قم بإزالة وظيفة تسجيل الدخول وإعادة التوجيه إلى عنوان URL الذي أنشأناه للتو في نماذج المستخدم.

# ... كميات

def login(request):
    if request.method == “POST”:
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(username=username, password=password)
        if user and user.profile.can_login < timezone.now(): # لاحظ أننا الآن نتحقق مما إذا كان بإمكان المستخدم تسجيل الدخول
            # قم بإزالة وظيفة Auth_login التي كانت هنا
            messages.success(request, 'Your password was accepted. Please continue.')
            if user.profile.mfa_enabled:
                return redirect(user.profile.create_auth_url()) # لاحظ أننا نعيد التوجيه إلى عنوان URL جديد هنا
            else: # إذا لم يستخدم المستخدم مصادقة متعددة العوامل ، فما عليك سوى تسجيل الدخول.
                auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
                return redirect('feed:feed')
        else: # إذا لم يكن تسجيل الدخول ناجحًا ،
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # هذا هو الجزء الذي نقوم فيه بتحديث ملف تعريف المستخدمين
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # لذلك لا يمكنهم تسجيل الدخول مرة أخرى لبضع ثوان
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
لذلك هذا أمر بسيط للغاية ، لدينا الآن طريقة لإعادة توجيه عرض مصادقة العامل عند إنشاءه. لدينا أيضًا استرداد في حالة عدم إضافة المستخدم رقم هاتف. سنضيف طريقة عرض أساسية لإضافة رقم هاتف قريبًا وتسجيل الدخول برسالة نصية قريبًا. أولاً ، نحتاج إلى طريقة سهلة لإرسال رسالة نصية من الكود الخاص بنا. للقيام بذلك ، يمكننا الاختيار من بين عدد من واجهات برمجة التطبيقات ، ولكن أسهل في رأيي هو Twilio. كما أنها توفر أسعارًا جيدة للمشاريع الأصغر ، بالإضافة إلى خصومات بالجملة. قم بإنشاء حساب على Twilio.com ، واملأ بعض التفاصيل حول مشروعك ، وشراء رقم هاتف ، ونسخ مفاتيح API إلى الإعدادات الخاصة بك. ثم ، أضف هذا الرمز تحت ملف جديد ، المستخدمين/sms.py.

nano users/sms.py

# استيراد جميع الحزم اللازمة
from django.utils import timezone
import random
import datetime
from django.conf import settings
from feed.middleware import get_current_request
from django.contrib import messages
import traceback

account_sid = settings.TWILIO_ACCOUNT_SID
auth_token = settings.TWILIO_AUTH_TOKEN
source_phone = settings.PHONE_NUMBER

# يرسل هذا الرمز النص مع Twilio
def send_text(target_phone, text):
    from twilio.rest import Client
    try:
        client = Client(account_sid, auth_token)
        if len(target_phone) >= 11:
            message = client.messages.create(
                to=target_phone,
                from_=source_phone,
                body=text)
    except:
        print(traceback.format_exc())

# وظيفة مساعد للحصول على رقم مع العديد من الأرقام
def get_num_length(num, length):
    n = ''
    for x in range(length):
        n = n + str(num)
    return int(n)

# أرسل النص للتحقق من المستخدم
def send_verification_text(user):
    length = user.profile.verification_code_length
    code = random.randint(get_num_length(1, length), get_num_length(9, length));
    user.profile.verification_code = code
    user.profile.mfa_code_expires = timezone.now() + datetime.timedelta(minutes=3)
    user.profile.save()
    send_user_text(user, "Your verification code for {} is {}".format(settings.SITE_NAME, str(code)))

# أرسل مستخدم أي نص مع هذه الوظيفة
def send_user_text(user, text):
    send_text(user.profile.phone_number, text)

# التحقق من صحة الرمز مع هذه الوظيفة
def check_verification_code(user, code):
    user.profile.mfa_attempts += 1
    result = user.profile.verification_code != None and code != '' and user.profile.verification_code == code and user.profile.mfa_code_expires > timezone.now() and user.profile.mfa_attempts <= 3
    if user.profile.mfa_attempts < 3 and result:
        user.profile.verification_code_length = 6
    elif user.profile.mfa_attempts > 2 and not result:
        user.profile.verification_code_length = 8
    user.profile.save()
    return result

# التحقق من صحة الوقت
def check_verification_time(user):
    result = user.profile.mfa_code_expires > timezone.now()
    return result
تأكد من تغيير إعداداتك بشكل مناسب ، وإضافة هذه الخطوط بمفاتيحك:

# تأكد من نسخها من لوحة معلومات Twilio الخاصة بك
TWILIO_ACCOUNT_SID = “<your sid>”
TWILIO_AUTH_TOKEN = “<your token>”
PHONE_NUMBER = “<your twilio phone number>”
SITE_NAME = “<Your site name>”
AUTH_VALID_MINUTES = 3 # عدد الدقائق التي تكون صفحة TFA نشطة بمجرد إنشاء مثيل لها
أولاً ، سنحتاج إلى أشكال لعوامل مصادقة العوامل لدينا. تحرير المستخدمين/forms.py ، أضف الرمز التالي.

# ... كميات
from django import forms

# نموذج لدخول رقم هاتفنا
class PhoneNumberForm(forms.Form):
    phone_number = forms.RegexField(regex=r'^\+?1?\d{9,15}$', error_messages = {'invalid': "Phone number must be entered in the format: '+999999999'. Up to 15 digits is allowed."})
    def __init__(self, *args, **kwargs):
        super(PhoneNumberForm, self).__init__(*args, **kwargs)
        self.fields['phone_number'].label = phone_number_label

# نموذج للمصادقة
class TfaForm(forms.Form):
    code = forms.IntegerField(required=False)
    def __init__(self, *args, **kwargs):
        super(TfaForm, self).__init__(*args, **kwargs)
        self.fields['code'].widget.attrs.update({'autocomplete': 'off'})
    help_texts = {
        'code': 'Please enter the six digit code after sending it to your phone with the button above.'
    }
بعد ذلك ، دعنا ننشئ طرق العرض في المستخدمين/views.py

# ... كميات
from django.http import HttpResponseRedirect
from .forms import PhoneNumberForm, TfaForm

def mfa(request, username, token):
    user = User.objects.filter(profile__uuid=username).first()
    if not user: return HttpResponseRedirect(reverse('verify:age') + '?next=' + request.GET.get('next') if request.GET.get('next') else '/go/' if request.user.is_authenticated and request.user.profile.vendor else '/' if request.user.is_authenticated else reverse('users:login'))
    user = get_object_or_404(User, profile__uuid=username)
    next = request.GET.get('next','')
    if not user.profile.mfa_enabled:
        if not check_verification_time(user):
            user.profile.mfa_enabled = False
            user.profile.enable_two_factor_authentication = True
            user.profile.phone_number = '+1'
            user.profile.save()
            print('Logging in user')
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
            messages.warning(request, 'Please enter a valid phone number and verify it with a code.')
            return redirect(reverse('users:mfa_onboarding'))
    if request.method == 'POST':
        form = TfaForm(request.POST)
        code = form.data['code']
        if code and code != '' and code != None:
            token_validated = user.profile.check_auth_token(token)
            p = user.profile
            is_verified = check_verification_code(user, int(code))
            p.mfa_authenticated = is_verified
            if token_validated:
                if is_verified:
                    user.profile.mfa_enabled = True
                    user.profile.save()
                    auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
                    p.verfication_code = None
                    p.uid = get_uuid()
                    p.save()
                    messages.success(request, 'You have been authenticated. Welcome.')
                    qs = '?'
                    for key, value in request.GET.items():
                        qs = qs + key + '=' + value + '&'
                    if next != '' and not (next.startswith('/accounts/logout/') or next.startswith('/accounts/login/') or next.startswith('/admin/login/') or next.startswith('/accounts/register/')):
                        return HttpResponseRedirect(ext)
                    elif next.startswith('/accounts/logout/') or next.startswith('/accounts/login/') or next.startswith('/accounts/register/'):
                        return redirect('feed:feed')
                    elif request.META.get('HTTP_REFERER', '/').startswith('/accounts/login/'):
                        return redirect(reverse('feed:feed'))
                    elif not next:
                        return redirect(reverse('feed:feed')
                    else:
                        return HttpResponseRedirect('feed:feed')
                else:
                    messages.warning(request, 'The code you entered was not recognized. Please try again.')
            elif not token_validated:
                messages.warning(request, 'The URL token has expired or was not recognized. Please try again.')
                logout(request)
                return redirect(reverse('users:login'))
            if p.mfa_attempts > 3:
                messages.warning(request, 'You have entered the incorrect code more than 3 times. please send yourself a new code.')
                p.verification_code = None
                p.save()
        elif user.profile.can_send_mfa < timezone.now():
            user.profile.mfa_attempts = 0
            user.profile.can_send_mfa = timezone.now() + datetime.timedelta(minutes=2)
            user.profile.save()
            send_verification_text(user)
            messages.success(request, "Please enter the code sent to your phone number. The code will expire in 3 minutes.")
        else:
            messages.warning(request, 'You are sending too many two factor authentication codes. Wait a few minutes before sending another code.')
    form = TfaForm()
    hide_logo = None
    if user.profile.hide_logo:
        hide_logo = True
    return render(request, 'users/mfa.html', {'title': 'Enter Code', 'form': form, 'xsmall': True, 'user': user, 'hide_logo': hide_logo, 'accl_logout': user.profile.shake_to_logout, 'preload': False})

@login_required
def mfa_onboarding(request):
    if request.method == 'POST':
        form = PhoneNumberForm(request.POST)
        request.user.profile.phone_number = form.data['phone_number'].replace('-', '').replace('(','').replace(')','')
        request.user.profile.mfa_enabled = True
        request.user.profile.enable_two_factor_authentication = True
        request.user.profile.save()
        messages.success(request, 'You have added a phone number to your account.')
        user = request.user
        return redirect(user.profile.create_auth_url())
    form = PhoneNumberForm(initial={'phone_number': request.user.profile.phone_number if request.user.profile.phone_number else '+1'})
    return render(request, 'users/mfa_onboarding.html', {'title': 'Enter your phone number', 'form': form, 'small': True})
سنحتاج أيضًا إلى قوالب لكل من هذه الآراء. دعنا نضيف قالب MFA أولاً.

nano users/templates/users/mfa.html
أضف رمز HTML هذا إلى القالب
 
{% extends 'base.html' %}
{% block content %}
{% load app_filters %}
{% load crispy_forms_tags %}
        <form action="{{ request.path }}{% if request.GET.next %}?next={{ request.GET.next }}{% endif %}" method="POST">
            {% csrf_token %}
            <legend class="border-bottom mb-4">Enter Verification Code</legend>
            <p>Step 1: Send the code</p>
	    <i>Never share your code with anyone, as it can be used to access your account temporarily.</i>
	    <div class="form-group">
                <button class="btn btn-outline-primary" type="submit">Send code</button>
            </div>
	    <hr>
	    <p>Step 2: Enter the code</p>
            <fieldset class="form-group">
                {{ form|crispy }}
		<p>Press the enter button to send yourself the code at {{ user.profile.phone_number|securephone }}. Then, enter the code and press enter.</p>
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-secondary" type="submit">Enter code</button>
            </div>
        </form>
{% endblock %}
 
هذا هو توضيح الذات جميلة. يرسل النموذج إما رمز أو رمز فارغ ، وسوف تلاحظ في العرض نرسل الرمز إذا تلقينا رمزًا فارغًا. ثم لدينا فقط زرين إرسال ، وبهذه الطريقة يمكننا إرسال الرمز مع أي من الزر. بعد ذلك ، سنضيف نموذجًا بسيطًا لإضافة رقم هاتف.

nano users/templates/users/mfa_onboarding.html
أضف HTML التالي:
 
{% extends 'base.html' %}
{% block content %}
{% load crispy_forms_tags %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Set Up Two Factor Authentication</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-secondary" type="submit">Add phone number</button>
            </div>
        </form>
{% endblock %}
 
هذا النموذج أبسط بكثير ، فهو يجعل نموذج رقم الهاتف الذي أنشأناه ويتيح للمستخدم إضافة رقم هاتف. هذا يبدو جيدا حقا! طالما تم إعداد كل شيء بشكل صحيح ، يجب أن نكون قادرين على إرسال الرسائل ، وتسجيل المستخدم برقم هاتفه بمجرد إضافة أنماط عنوان URL. آخر شيء نحتاج إلى إعداده هو عرض ملف تعريف للملف الشخصي حتى نتمكن من التأكد من أن المستخدم يمكنه تغيير رقم هاتفه دون تسجيل الدخول. أيضًا ، في النهاية نريد إضافة خيار "توقف إلى الإقلاع" ، حتى يتمكن المستخدم من إرسال الرسائل النصية "توقف" عن إلغاء الاشتراك في الرسائل النصية المستقبلية. دعنا نضيف طريقة عرض ملف تعريف إلى المستخدمين/views.py. ستقوم طريقة العرض هذه بتحديث السيرة الذاتية للمستخدم والبريد الإلكتروني واسم المستخدم ورقم الهاتف ، بالإضافة إلى السماح لنا بتمكين المصادقة متعددة العوامل. أولاً ، سنحتاج إلى نموذجين آخرين في المستخدمين/الأشكال

# ... المبالغ
class UserUpdateForm(forms.ModelForm):
    email = forms.EmailField()
    class Meta:
        model = User
        fields = ['username', 'email']

phone_number_label = 'Phone number (no spaces, parenthesis \'(\' or dashes \'-\', numbers beginning with + only)'

class ProfileUpdateForm(forms.ModelForm):
    subscribed = forms.BooleanField(required=False)
    phone_number = forms.CharField(required=False)
    def __init__(self, *args, **kwargs):
        super(ProfileUpdateForm, self).__init__(*args, **kwargs)
    class Meta:
        model = Profile
        fields = ['bio', 'phone_number', 'enable_mfa', 'subscribed']
بعد ذلك ، يمكننا إنشاء طريقة عرض لاستخدام كلا هذين النموذجين. تحرير المستخدمين/views.py وأضف في العرض.

# أضف هذه الواردات
from .forms import UserUpdateForm, ProfileUpdateForm
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_exempt
from .models import Profile
from .mfa import send_user_text

@csrf_exempt
@never_cache
@login_required
def profile(request):
    if request.method == 'POST':
        u_form = UserUpdateForm(request.POST, instance=request.user)
        p_form = ProfileUpdateForm(request.POST,
                                       request.FILES,
                                       instance=request.user.profile)
        if u_form.is_valid() and p_form.is_valid():
            new_phone_number = p_form.data['phone_number']
            u_form.save()
            profile = p_form.save(commit=False)
            profile.phone_number = profile.phone_number.replace('-', '').replace('(','').replace(')','')
            profile.save()
            if new_phone_number != oldprofile.phone_number and oldprofile.phone_number and len(oldprofile.phone_number) >= 11:
                profile.mfa_enabled = True
                profile.save()
                send_text(oldprofile.phone_number, 'Your phone number has been updated to ' + new_phone_number + '. Please refer to texts on that phone to log in. If you didnt make this change, please call us. - {}'.format(settings.SITE_NAME))
            if profile.enable_two_factor_authentication and profile.phone_number and len(profile.phone_number) < 11:
                profile.enable_two_factor_authentication = False
                messages.success(request, f'Two factor authentication can\'t be activated without entering a phone number. Please enter a phone number to enable two factor authentication.')
            profile.save()
            if new_phone_number != oldprofile.phone_number and new_phone_number and len(new_phone_number) >= 11:
                send_user_text(request.user, 'You have added this number to {} for two factor authentication. You can now use your number for two factor authentication. If you didnt make this change, please call us. - {}'.format(settings.SITE_NAME, settings.DOMAIN))
                profile.mfa_enabled = True
                profile.mfa_code_expires = timezone.now() + datetime.timedelta(minutes=3)
                profile.save()
                return redirect(profile.create_auth_url())
            messages.success(request, f'Your profile has been updated!')
            print('Profile updated')
            return redirect('users:profile')
    else:
        u_form = UserUpdateForm(instance=request.user)
        p_form = ProfileUpdateForm(instance=request.user.profile, initial={'phone_number': request.user.profile.phone_number if request.user.profile.phone_number else '+1'})
    context = {
        'u_form': u_form,
        'p_form': p_form,
        'title':'Update Your Profile',
    }
    return render(request, 'users/profile.html', context)
سنحتاج أيضًا إلى قالب لهذا العرض.

nano users/templates/users/profile.html
 
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% load feed_filters%}
{% block content %}
	<h2>Edit Your Profile</h2>  
	<form method="POST" enctype="multipart/form-data" id="profile-form">
          {% csrf_token %}
          <fieldset class="form-group">
              <legend class="border-bottom mb-4 mt-4">Profile info</legend>
              {{ u_form|crispy }}
              {{ p_form|crispy }}
          </fieldset>
          <div class="form-group">
              <button class="btn btn-outline-info" type="submit">Update}</button>
          </div>
	</form>
        <p style="text-color: green;" class="hide" id="posted">Saved</p>

{% endblock content %}
{% block javascript %}
var form = document.getElementById('profile-form');
$('input').change(function(){
	var formdata = new FormData(form);
	$.ajax({
		url: window.location.href,
		type: "POST",
		data: formdata,
		processData: false,
		contentType: false,
		timeout: 1000 * 60,
                success: function(data) {
                  $(posted).removeClass("hide");
		  setTimeout(function() {
			$(posted).addClass("fade-hidden");
			setTimeout(function() {
				$(posted).addClass("hide");
				$(posted).removeClass("fade-hidden");
			}, 2000);
		  }, 2000);
                }
	});
});
{% endblock %}
 
ستلاحظ أن هذا نموذج بسيط إلى حد ما ، ولكن يحتوي على بعض JavaScript الذي ينشر تلقائيًا محتويات النموذج عند تحديثها. من المفيد أن يكون لديك ، لذلك يمكنك إجراء تعديلات دون الحاجة إلى الضغط على الإرسال في كل مرة. بعد ذلك ، نحتاج إلى عناوين URL التي تمثل كل هذه المشاهدات في URL URL Patters. تحرير المستخدمين/urls.py وأضف هذا الرمز:

# ... الرمز السابق ، والواردات
from django.urls import path
from . import views

app_name='users'

urlpatterns = [
# ... أنماط URL التي أدخلناها مسبقًا ، أضف الأسطر الثلاثة التالية
    path('mfa/<str:username>/<str:token>/', views.mfa, name='mfa'),
    path('mfa/onboarding/', views.mfa_onboarding, name='mfa_onboarding'),
    path('profile/', views.profile, name='profile'),
]
الآن هو الوقت المناسب لاختبار مشروعنا. لكن أولاً ، دعنا ندير نسخة احتياطية أخرى.

backup
وتشغيل الخادم. قبل أن ننشر على خادم Linux ، من الجيد تمكين مصادقة عاملين على الحساب. سنفعل ذلك إلى عنوان URL الخاص بنا ،/المستخدمين/الملف الشخصي/، والتحقق من المربع لتمكين المصادقة بعد إدخال رقم هاتفنا ، ثم إرسال النموذج.

python manage.py runserver localhost:8000
تفضل بزيارة صفحة الويب عن طريق الانتقال إلى متصفح الويب الخاص بك ، وأنا أستخدم Google Chrome في هذا المثال ، وإدخال عنوان URL https: // localhost: 8000/حساب/ملف تعريف ستتمكن من تسجيل الدخول إذا لزم الأمر وتمكين مصادقة عاملان. يحتاج هذا المشروع إلى خادم لتشغيله حتى يتمكن حقًا من إرسال بريد. لكن أولاً ، نحتاج إلى طريقة لرؤية الأخطاء. ستلاحظ أنه إذا قمت بتشغيل الخادم في وضع التصحيح ، مع إعدادات. لإظهار الأخطاء دون استخدام وضع التصحيح ، وهو غير آمن على خادم الإنتاج ، يجب أن نضيف طريقة عرض لذلك. أهم الأخطاء التي نحتاج إلى التعامل معها هي: خطأ 500 - مشكلة في الكود لدينا خطأ 404 - صفحة لم يتم العثور عليها (عنوان URL المكسور) خطأ 403 - خطأ تم رفض الإذن دعنا نضيف تطبيقًا جديدًا للتعامل مع هذه الأخطاء ، يسمى الأخطاء.

python manage.py startapp errors
أضف هذا إلى الإعدادات .Py كما فعلنا من قبل ، في إعداد installed_apps ، وابدأ بإضافة إشارات إلى بعض المشاهدات في App/urls.py ، حيث يكون التطبيق هو اسم مشروع Django الخاص بك.

handler404 = 'errors.views.handler404'
handler500 = 'errors.views.handler500'
handler403 = 'errors.views.handler403'
هذا كل ما نحتاجه إلى جانب طرق عرض الخطأ والقوالب وقليل من الوسيطة. دعونا نحدد تلك كما:

from django.shortcuts import render, redirect
from django.http import HttpResponse
from stacktrace.models import Error
from errors.middleware import get_current_exception
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import user_passes_test
from .logs import get_logs
from face.tests import is_superuser_or_vendor
from django.views.decorators.csrf import csrf_exempt
from errors.highlight import highlight_code
from django.shortcuts import redirect
from django.urls import reverse

# قم بإنشاء وجهات نظرك هنا.
@login_required
@user_passes_test(is_superuser_or_vendor)
def logs(request):
    logs = highlight_code(get_logs())
    return render(request, 'errors/live_error.html', {'title': 'Error Logs', 'pagetitle': 'Error Logs', 'notes': 'These are the recent error logs.', 'trace': logs, 'full': True})

@login_required
@user_passes_test(is_superuser_or_vendor)
def logs_api(request):
    logs = highlight_code(get_logs())
    return HttpResponse(logs)

@login_required
def handler404(request, exception):
    if not request.path.endswith('/'): return redirect(request.path + '/')
    return render(request, 'errors/error.html', {'title': 'Error 404', 'pagetitle': 'Error 404', 'notes': 'This page was not found on the server. It may have moved or been deleted.', 'is_404': True})

def handler500(request):
    print(get_current_exception())
    user = None
    if hasattr(request, 'user') and request.user and request.user.is_authenticated:
        user = request.user
    try:
        Error.objects.create(user=user, stack_trace=get_current_exception(), notes='Logged by 500 handler.')
    except: pass
    return render(request, 'errors/error.html', {'title': 'Error 500', 'pagetitle': 'Error 500', 'notes': 'There is a problem with the server, or with a request coming from you. Thank you for your understanding while we get things set up.', 'trace': get_current_exception()})

def handler403(request, exception):
    return render(request, 'errors/error.html', {'title': 'Error 403', 'pagetitle': 'Error 403', 'notes': 'You don\'t have permission to preform this request. If you think this is in error, please contact the server administrator.', 'is_403': True})

def handler400(request, exception):
    return render(request, 'errors/error.html', {'title': 'Error 400', 'pagetitle': 'Error 400', 'notes': 'This was a bad request.'})
بعد ذلك ، دعنا نحدد البرامج الوسيطة للتعامل مع هذه الأخطاء. سنقوم بذلك عن طريق الإضافة أولاً إلى Middleware_Classes في الإعدادات.

MIDDLEWARE_CLASSES = [
    # ... الوسيطة السابقة
    'errors.middleware.ExceptionVerboseMiddleware,
]
بعد ذلك ، دعنا نضيف البرامج الوسيطة.

from threading import local
import traceback
from django.utils.deprecation import MiddlewareMixin

_error = local()

class ExceptionVerboseMiddleware(MiddlewareMixin):
    def process_exception(self, request, exception):
        _error.value = traceback.format_exc()

def get_current_exception():
    try:
        return _error.value
    except AttributeError:
        return None

def set_current_exception(exception):
    try:
        _error.value = exception
    except AttributeError:
        print('Attribute error setting exception.')
نضيف وظيفة للحصول على الاستثناء الحالي باستخدام ترابط محلي ، مما يساعدنا على تتبع أي أخطاء في التعليمات البرمجية الخاصة بنا. من حيث القوالب ، نحتاج فقط إلى واحدة ، لأننا نحدد العنوان ديناميكيًا في العرض. يحتاج القالب فقط إلى تقديم العنوان و "تتبع" ، وتتبع الخطأ لدينا من السياق.

nano errors/templates/errors/error.html
 
{% extends 'base.html' %}
{% block content %}
<h1>{{ pagetitle }}</h1>
<p>{{ trace }}</p>
{% endblock %}
 
هذا هو أبسط قالبنا حتى الآن ، ولكن هذا هو مدى سهولة رؤية الأخطاء في مشروعنا. بعد ذلك ، دعنا نتعطش تصحيح الأخطاء في الإعدادات.

nano app/settings.py
ابحث عن هذا الخط حيث يتم ضبطه على صحيح ، وقم بتغييره إلى خطأ

DEBUG = False
المضي قدما والنسخ الاحتياطي التطبيق الآن. نحن على استعداد للنشر على خادم Linux عن بُعد ، ومواصلة إضافة ميزات من هناك.

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

nano users/models.py
هذا ما يجب أن يبدو عليه النموذج الذي نضيفه. لا نحتاج إلى أي طرق ، فقط متغيرات لتخزين معرف ، والمستخدم ، والطابع الزمني ، والانتهاء من الطول ، ومحاولات ضد أي مصادقة متعددة العوامل (رمز مثل 123456 تم إرساله إلى هاتف أو بريد إلكتروني).

# رمز أساسي يستخدم لتسجيل الدخول إلى الموقع
class MFAToken(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='mfa_tokens')
    timestamp = models.DateTimeField(default=timezone.now)
    expires = models.DateTimeField(default=timezone.now)
    token = models.CharField(default='', max_length=100)
    length = models.IntegerField(default=6)
    attempts = models.IntegerField(default=0)
    uid = models.CharField(default=uuid.uuid4, max_length=100)
دعنا نضيف أيضًا امتيازًا لمستخدمنا ، وسنقوم بتعيينه يدويًا في الوقت الحالي ، قبل الترحيل في النهاية إلى تجنيد المستخدمين المميزين تلقائيًا. في نماذج المستخدم ، أضف هذا السطر في الملف الشخصي:

    vendor = models.BooleanField(default=False)
كما هو الحال مع أي تغييرات على قاعدة البيانات ، نحتاج إلى إجراء عمليات ترحيل وترحيل قاعدة البيانات في أي وقت نقوم فيه بتحرير ملف models.py في Django. تذكر ، للقيام بذلك ، نستخدم المصدر أولاً (إذا لم يتم استخدامه بالفعل منذ أن كانت المحطة مفتوحة) ومن ثم Python Manage.py لإجراء الترحيل والترحيل.

cd project-directory-you-named # (إذا لزم الأمر)
source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
في الوقت الحالي ، يمكنك تجنيد أي حسابات قمت بإنشائها كبائعين باستخدام Shell.

python manage.py shell
from users.models import Profile
p = Profile.objects.get(user__username='Charlotte')
p.vendor = True
p.save()
exit()
الآن ، دعنا نطور طريقة عرض مصادقة العوامل المتعددة لاستخدام هذا الرمز المميز. أولاً ، نحتاج إلى تعديل أدوات المساعدة المساعد MFA. باستخدام نانو ،

nano users/mfa.py

from django.utils import timezone
import random
import datetime
from django.conf import settings
from feed.middleware import get_current_request
from django.contrib import messages
from .email import send_html_email
import traceback
from .models import MFAToken

account_sid = settings.TWILIO_ACCOUNT_SID
auth_token = settings.TWILIO_AUTH_TOKEN
source_phone = settings.PHONE_NUMBER

def send_text(target_phone, text):
    from twilio.rest import Client
    try:
        client = Client(account_sid, auth_token)
        if len(target_phone) >= 11:
            message = client.messages.create(
                to=target_phone,
                from_=source_phone,
                body=text + ' Text STOP to cancel.')
    except:
        messages.warning(get_current_request(), 'There was an error sending the message.')
        print(traceback.format_exc())

def get_num_length(num, length):
    n = ''
    for x in range(length):
        n = n + str(num)
    return int(n)

def send_verification_text(user, token):
    length = user.profile.verification_code_length
    code = random.randint(get_num_length(1, length), get_num_length(9, length));
    token.token = code
    token.expires = timezone.now() + datetime.timedelta(minutes=settings.AUTH_VALID_MINUTES)
    token.save()
    send_user_text(user, "Your verification code for {} is {}".format(settings.SITE_NAME, str(code)))

def send_verification_email(user, token):
    length = user.profile.verification_code_length
    code = random.randint(get_num_length(1, length), get_num_length(9, length));
    token.token = code
    token.expires = timezone.now() + datetime.timedelta(minutes=settings.AUTH_VALID_MINUTES)
    token.save()
    send_html_email(user, "Your verification code for {} is {}".format(settings.SITE_NAME, str(code)), "<p>Dear {},</p><p>Your verification code for {} is {}. Thank you for using this code to secure your account.</p><h2>{}</h2><p>Sincerely, {}</p>".format(user.profile.name, settings.SITE_NAME, str(code), str(code), settings.SITE_NAME))

def send_user_text(user, text):
    send_text(user.profile.phone_number, text)

def check_verification_code(user, token, code):
    token.attempts = token.attempts + 1
    profile = user.profile
    result = (token != None and code != '' and token.token == code and (token.expires > timezone.now()) and token.attempts <= settings.MFA_TOKEN_ATTEMPTS)
    if token.attempts < 3 and result:
        profile.verification_code_length = 6
    elif token.attempts > 1 and not result:
        profile.verification_code_length = profile.verification_code_length + 2
        if profile.verification_code_length > settings.MFA_TOKEN_LENGTH: profile.verification_code_length = settings.MFA_TOKEN_LENGTH
    token.save()
    profile.save()
    return result

# مصادقة المستخدم باستخدام بريده الإلكتروني أو رقم هاتفه
def mfa(request, username, usertoken):
    token = MFAToken.objects.filter(uid=username, expires__gt=timezone.now() + datetime.timedelta(seconds=30)).order_by('-timestamp').last() # قم بتصفية الرمز المميز بالقيمة التي تم تمريرها في عنوان URL (AUID)
    if not token: token = MFAToken.objects.create(user=User.objects.filter(profile__uuid=username).first(), uid=username, expires=timezone.now() + datetime.timedelta(seconds=115)) # إذا لم يتم إنشاء هذه الجلسة ، فقم بإنشائها
    user = User.objects.filter(id=token.user.id).first() # احصل على المستخدم من الرمز المميز
    if not user and request.user.is_authenticated: return redirect(reverse('feed:home')) # إذا تم مصادقتهم بالفعل ، فقم بتسجيل الدخول
    if not user: raise PermissionDenied() # إنكار إذا لم يتم العثور على مستخدم
    next = request.GET.get('next','')
    if not user.profile.enable_two_factor_authentication and user.is_active and user.profile.check_auth_token(usertoken, token): # تحقق من رمز المصادقة
        auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # قم بتسجيل الدخول إلى المستخدم إذا لم يتم تسجيل الدخول بالفعل
        user.profile.mfa_expires = timezone.now() + datetime.timedelta(minutes=settings.LOGIN_VALID_MINUTES) # اضبط انتهاء صلاحية مصادقة العوامل المتعددة
        user.profile.save()
        return HttpResponseRedirect(next if next != '' else reverse('landing:landing')) # إعادة توجيه المستخدم إلى الصفحة التالية
    if not user.profile.mfa_enabled: # تحقق مما إذا تم تمكين MFA
        if not check_verification_time(user, token): # تحقق من الوقت
            user.profile.mfa_enabled = False # امسح رقم الهاتف
            user.profile.enable_two_factor_authentication = True # تمكين MFA
            user.profile.phone_number = '+1' # تعطيل رقم الهاتف
            user.profile.save() # حفظ الملف الشخصي
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # قم بتسجيل المستخدم في إذا لم يتم تمكين MFA الخاص بهم
            messages.warning(request, 'Please enter a valid phone number and verify it with a code.')
            return redirect(reverse('users:mfa_onboarding'))
    if request.method == 'POST' and not fraud_detect(request, True): # إذا كان الطلب هو طلب نشر
        form = TfaForm(request.POST) # مثيل للنموذج
        code = str(form.data.get('code', None)) # احصل على الرمز
        if code and code != '' and code != None: # تأكد من أنها ليست فارغة
            token_validated = user.profile.check_auth_token(usertoken) # تحقق من رمز المصادقة
            p = user.profile
            is_verified = check_verification_code(user, token, code) # تحقق من الرمز
            p.mfa_authenticated = is_verified
            if token_validated: # إذا كان كل شيء
                if is_verified: # بالترتيب
                    user.profile.mfa_enabled = True # تمكين MFA (إن لم يكن ممكّنًا بالفعل)
                    user.profile.save()
                    auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # تسجيل الدخول إلى المستخدم
                    face = user.faces.filter(session_key=None).last() 
                    p.mfa_expires = timezone.now() + datetime.timedelta(minutes=settings.LOGIN_VALID_MINUTES)
                    p.save()
                    messages.success(request, 'You have been authenticated. Welcome.')
                    qs = '?'
                    for key, value in request.GET.items(): # بناء Querystring للمعلمة التالية (إن وجدت)
                        qs = qs + key + '=' + value + '&'
                    if next != '' and not (next.startswith('/accounts/logout/') or  next.startswith('/accounts/login/') or next.startswith('/admin/login/') or next.startswith('/accounts/register/')):
                        return HttpResponseRedirect(next) # إعادة توجيه
                    elif next.startswith('/accounts/logout/') or next.startswith('/accounts/login/') or next.startswith('/accounts/register/'):
                        return redirect(reverse('/'))
                    elif request.META.get('HTTP_REFERER', '/').startswith('/accounts/login/'):
                        return redirect(reverse('/'))
                    elif not next:
                        return redirect(reverse('/'))
                    else:
                        return HttpResponseRedirect(reverse('verify:age') + '?next=' + request.META.get('HTTP_REFERER', '/'))
                else:
                    messages.warning(request, 'The code you entered was not recognized. Please try again.')
            elif not token_validated: # إذا كان الرمز غير صالح
                messages.warning(request, 'The URL token has expired or was not recognized. Please try again.')
                logout(request)
                return redirect(reverse('users:login'))
            if p.mfa_attempts > 3: # إذا كان هناك الكثير من المحاولات
                messages.warning(request, 'You have entered the incorrect code more than 3 times. please send yourself a new code.')
                p.verification_code = None
                p.save()
        elif user.profile.can_send_mfa < timezone.now():
            user.profile.mfa_attempts = 0
            user.profile.can_send_mfa = timezone.now() + datetime.timedelta(minutes=2)
            user.profile.save()
            if form.data.get('send_email', False): # أرسل البريد الإلكتروني (أو النص)
                send_mfa_verification_email(user, token)
            else:
                send_verification_text(user, token)
            messages.success(request, "Please enter the code sent to your phone number or email. The code will expire in 3 minutes.")
        elif user.profile.can_send_mfa < timezone.now() + datetime.timedelta(seconds=115):
            messages.warning(request, 'You are sending too many two factor authentication codes. Wait a few minutes before sending another code.')
    form = TfaForm()
    hide_logo = None
    if user.profile.hide_logo:
        hide_logo = True
    if request.user.is_authenticated: return redirect(reverse('/'))
    # تقديم النموذج (للحصول على طلبات الحصول على)
    return render(request, 'users/mfa.html', {'title': 'Enter Code', 'form': form, 'xsmall': True, 'user': user, 'hide_logo': hide_logo, 'accl_logout': user.profile.shake_to_logout, 'preload': False, 'autofocus': request.method == 'POST'})
عندما نضيف في هذا الرمز ، تأكد من استيراد الوظيفة لإرسال بريد إلكتروني. في الجزء العلوي من الملف ، طرق عرض المستخدم (مع الواردات الأخرى) ، أضف

from .mfa import send_verification_email as send_mfa_verification_email
الآن ، نحتاج إلى كتابة هذه الوظيفة قبل أن تعمل أي من هذا. يجب أن يوسع وظيفة إرسال البريد الإلكتروني الخاصة بنا ، وببساطة إرسال بريد إلكتروني إلى المستخدم برمز التحقق.

nano users/mfa.py

def send_verification_email(user, token):
    length = user.profile.verification_code_length
    code = random.randint(get_num_length(1, length), get_num_length(9, length));
    token.token = code
    token.expires = timezone.now() + datetime.timedelta(minutes=settings.AUTH_VALID_MINUTES)
    token.save()
    send_html_email(user, "Your verification code for {} is {}".format(settings.SITE_NAME, str(code)), "<p>Dear {},</p><p>Your verification code for {} is {}. Thank you for using this code to secure your account.</p><h2>{}</h2><p>Sincerely, {}</p>".format(user.profile.name, settings.SITE_NAME, str(code), str(code), settings.SITE_NAME))
لذلك كل هذا يعمل بشكل رائع ، والآن لدينا نظام مصادقة متعدد العوامل يعتمد على رقم هاتف أو بريد إلكتروني لتسجيل الدخول. لكننا نحتاج أيضًا إلى طريقة لإزالة المستخدمين الذين لا يتعاونون مع شروطنا على الأقل. يمكن أن تكون هذه مرسلة البريد العشوائي أو الروبوتات أو أي شخص لا يعني جيدًا لعملنا. ألقِ نظرة على عرض لدي لمراقبة المستخدمين على موقع الويب الخاص بي:

# المبالغ
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import user_passes_test
from .tests import is_superuser_or_vendor # سنحتاج إلى إنشاء هذا الاختبار

@login_required
@user_passes_test(is_superuser_or_vendor)
def users(request):
    # احصل على قائمة المستخدمين
    new_today = User.objects.filter(is_active=True, date_joined__gte=timezone.now() - datetime.timedelta(hours=24)).count()
    new_this_month = User.objects.filter(is_active=True, date_joined__gte=timezone.now() - datetime.timedelta(hours=24*30)).count()
    subscribers = User.objects.filter(is_active=True, profile__subscribed=True).count()
    return render(request, 'users/users.html', { # إرجاع المستخدمين في قالب
        'title': 'All Accounts',
        'users': User.objects.all(),
        'new_today': new_today,
        'new_this_month': new_this_month,
        'subscribers': subscribers
    })
لاحظ أن هذا الرمز يستخدم اختبارًا ، سنحتاج إلى إعلان هذا الاختبار في ملف tests.py واستيراده. تحرير المستخدمين/الاختبارات ، دعنا ننشئ الاختبار.

def is_superuser_or_vendor(user):
    return user.profile.vendor or user.is_superuser
هذا بالتزامن مع قالب المستخدمين/المستخدمين. html ، والذي يبدو مثل هذا:
 
{% extends 'base.html' %}
{% load app_filters %}
{% block content %}
<h1>All Registered Visitors</h1>
<p>{{ new_today|nts|capitalize }} new today, {{ new_this_month|nts }} new this month, {{ subscribers|nts }} subscribers, {{ users.count|nts }} total.</p>
<hr style="color: red;">
{% for user in users %}
{% include 'users/_user.html' %}
<hr style="color: blue;">
{% endfor %}
{% endblock %}
 
لاحظ أن القالب يتضمن قالبًا آخر ، المستخدمين/_User.html. عند استخدام قالب يحتوي على موظف فرعي وعدم استخدامه ، من الجيد إضافة سطحي (_) قبل اسم الملف لتمديده ، من أجل التمييز بين القوالب. لاحظ أن هذا كثير من Jinja ، قد لا يكون لديك كل هذه المتغيرات محددة. ولكن هذا ما يبدو عليه رمزتي.
 
{% load app_filters %}
<div>
<img src="{{ user.profile.get_image_url }}" alt="@{{ user.profile.name }}'s profile photo" width="120" height="120" align="left" style="margin-top:5px; margin-right:10px; margin-bottom:10px; border-radius: 50%;"/>
    <div class="article-metadata">
      <p class="mr-2">@{{ user.username }} - {{ user.profile.name }} ({{ user.profile.preferred_name }})</p>
      <small class="text-muted">Last seen {{ user.profile.last_seen|date:"F d, Y" }} {{ user.profile.last_seen|time:"H:i" }}</small>
      <small class="text-muted">Joined on {{ user.profile.date_joined|date:"F d, Y" }} {{ user.profile.date_joined|time:"H:i" }}</small>
      <small>{{ user.email }}</small>
      {% if user.profile.phone_number %}<small><i class="bi bi-phone-fill"></i>{{ user.profile.phone_number }}</small>{% endif %}
      {% if user.verifications.last %}
      <small>'{{ user.verifications.last.full_name }}'</small>
      <small><i class="bi bi-123"></i> {{ user.verifications.last.document_number }}</small>
      <small><i class="bi bi-calendar-heart-fill"></i> {{ user.verifications.last.birthdate }}</small>
      <a href="{{ user|document_front }}" class="btn btn-sm btn-outline-primary" title="ID front"><i class="bi bi-person-badge-fill"></i> ID front</a>
      <a href="{{ user|document_back }}" class="btn btn-sm btn-outline-primary" title="ID back"><i class="bi bi-upc-scan"></i> ID back</a>
      {% endif %}
      <small># {{user.id}} </small>
      <small>{% if user.profile.subscribed %}Subscribed{% else %}Not subscribed{% endif %}</small>
    </div>
    {%if not user.is_superuser %}
    <div style="float: right;">{% include 'users/toggle_active.html' %}</div>
    {% endif %}
    {% autoescape off %}    
    <p class="article-content">{{ user.bio }}</p>
    {% endautoescape %}
    <hr>
    <p>{% if user.profile.identity_verified %}Verified user.{% else %}Unverified user.{% endif %} Verifications: {{ user.verifications.count|nts }}</p>
 
نحتاج أيضًا إلى فرع آخر ، toggle_active.html. يجب أن يكون هذا القالب نموذجًا يسمح لنا بتبديل ما إذا كان المستخدم نشطًا.
 
<form style="display: inline-block;" action="{% url 'users:toggle-user-active' user.id %}" method="POST" id="publishForm">
<button class="btn btn-sm btn-outline-danger" type="submit">{% if user.is_active %}<i class="bi bi-eye-fill"></i>{% else %}<i class="bi bi-eye-slash-fill"></i>{% endif %}</button>
</form>
 
سنحتاج أيضًا إلى إضافة طريقة عرض لتبديل نشاط المستخدم وأنماط عنوان URL المناسبة. بينما نحن في ذلك ، دعنا نضيف طريقة عرض لحذف المستخدم في حال احتجنا إلى ذلك.

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
@login_required
@user_passes_test(is_superuser_or_vendor)
def toggle_user_active(request, pk):
    user = User.objects.get(id=pk)
    if request.method == 'POST':
        user.is_active = not user.is_active
        user.save()
    return HttpResponse('<i class="bi bi-eye-fill"></i>' if user.is_active else '<i class="bi bi-eye-slash-fill"></i>')


# المبالغ
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.views.generic import DeleteView

class UserDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = User
    success_url = '/' # إعادة توجيه عنوان URL للنجاح
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        return context

    def test_func(self): # اختبار إذا كان المستخدم Superuser ولديه إذن للحذف
        user = self.get_object()
        if self.request.user != user and self.request.user.is_superuser:
            return True
        return False
على الرغم من أن هذا أمر عملي عند الضرورة ، يجب ألا يكون حذف المستخدم ضروريًا معظم الوقت ، يمكننا فقط تبديل رؤية المستخدمين الذين يزورون الموقع إذا احتجنا إلى رفضهم. أنماط عنوان URL أضفنا تبدو هكذا. مع nano ، قم بتحرير المستخدمين/urls.py وأضف هذه الخطوط:

nano users/urls.py
يجب أن تسير الخطوط في قائمة المسارات في طرق عرض المستخدم ، قبل النهاية "] ولكن بعد البداية" [".

# ...
    path('user/<int:pk>/delete/', UserDeleteView.as_view(template_name='blog/user_confirm_delete.html'), name='delete-user'),
    path('user/<int:pk>/active/', views.toggle_user_active, name='toggle-user-active'),
# ...
الآن ، تأكد من نسخ احتياطي للموقع حتى تتمكن من تنزيله على خادم الويب ، سنواصل العمل عليه. من سطر الأوامر ،

sudo backup
الآن موقعنا مدعوم. حتى الآن لدينا بعض الميزات الأكثر فائدة. ولكن ماذا عن الصورة الكبيرة هنا؟ لا يزال هذا الرمز لا يمكن الوصول إليه من الإنترنت ، وليس لدينا أي خادم بريد حتى الآن ، ونحن بحاجة إلى توسيع تطبيقنا لتضمين عملية التحقق الشاملة بالإضافة إلى التخطيطات السلسة لمساعدتنا على استكشاف الموقع ، إلى جانب بروتوكولات آمنة لمصادقة المستخدمين المميزين . سوف نصل إلى كل هذا. أهم شيء في الوقت الحالي هو الحصول على هذا الرمز عبر الإنترنت ، والذي يمكننا القيام به مع بضعة أسطر من Bash على خادم Ubuntu. ستحتاج إلى استئجار خادم لهذا ، ما لم يكن لديك خادم في المنزل واشتراك عبر الإنترنت يتيح لك فتح المنافذ. أنا شخصياً أقوم بتشغيل موقع الويب الخاص بي على جهاز HP Z440 الذي تم تثبيته في شقتي ، ولكن عادة ما يكون الأمر أرخص بكثير للاحتياجات الأساسية لاستئجار خادم خاص افتراضي (VPS). ضع في اعتبارك أن الكود الذي نديره الآن نحيف نسبيًا ، وسوف تحتاج إلى الحفاظ عليه وتحسينه قبل أن نكونعلى استعداد لاستخدام ما لدينا لبناء منتج. تأكد من توخي الحذر مما تفعله بالإنترنت ، تأكد من نشر هذا الموقع علنًا على الويب على خادم Linux ، لديك خطة لمنع التفاعلات غير المرغوب فيها مع موقع الويب الخاص بك. من المحتمل أن يكون هذا يمثل مشكلة في البداية ، لكننا سنبحث في مجموعة متنوعة من الحلول لمكافحة هذا ، بما في ذلك التعلم الآلي والذكاء الاصطناعي ورؤية الكمبيوتر. عندما تصبح مشكلة ، انظر أكثر في هذا النص لحل ما. من حيث استئجار VPS ، هناك الكثير من الأماكن التي يمكنك الذهاب إليها. تحتوي Google Cloud على خوادم VPS و IonOS و Kamatera و Amazon AWS والمزيد من مقدمي الخدمات التي تقدم حلولًا لخادم السحابة تناسب احتياجاتنا. ستحتاج إلى النقر من خلال نماذجهم وتحديد خطة للبدء. يمكنك الذهاب مع خطة أساسية مع أي مزود ، ولكن تأكد من أن المزود يسمح لك بفتح منافذ خادم بريد المنافذ لإرسال بريد إلكتروني (يجب أن يكون هذا المنفذ 587 والمنفذ 25) ، بعض مقدمي الخدمات يحظرون هذه المنافذ. حتى الآن لديEST Experience with Ionos و Kamatera ، سيسمح لي كلاهما بإرسال بريد إلكتروني غير محدود وأسعارهما رخيصة جدًا. سوف تتصل بخادمك الجديد عبر بروتوكول يسمى SSH أو Secure Shell ، والذي يتيح لك الواجهة عن بُعد مع الخادم تمامًا مثل جهاز الكمبيوتر الشخصي الخاص بك ، من جهاز الكمبيوتر الشخصي الخاص بك. عند إعداد الخادم ، من المحتمل أن يطلب منك مزود الاستضافة إضافة مفتاح SSH ، أو سيعطيك اسم مستخدم وكلمة مرور. مفتاح SSH هو كيفية تسجيل الدخول إلى الخادم من سطر الأوامر لتحرير الرمز. استخدم خيارات SSH-Keygen أدناه لإنشاء SSH

ssh-keygen
احفظ الملف واكتبه إذا كنت بحاجة إلى ذلك ، فمن الجيد تدوير مفاتيح SSH إذا لم تكن قد لم تكن بالفعل. الآن ، يمكنك استخدام الأمر التالي لرؤية مفتاح SSH الخاص بك. سترغب في نسخه إلى الخادم البعيد الخاص بك حتى تتمكن من استخدامه للمصادقة.

cat ~/.ssh/id_rsa.pub
إذا لم تكن قادرًا على رؤية مفتاح SSH عند كتابة هذا الأمر (سلسلة طويلة من الأرقام والحروف التي تبدأ بـ "SSH-RSA AAA") ، فحاول إنشاء مفتاح RSA (فهي أكثر أمانًا ، لذلك أنصحت باستخدامها .) سوف يولد الرمز التالي مفتاح RSA SSH 4096 بت.

ssh-keygen -t rsa -b 4096
قم بإنشاء VPs تقوم بتشغيل Ubuntu ، ولكنك تخطط للقيام بذلك. بمجرد إنشاء VPS من خلال النقر من خلال النماذج على موقع مقدمي الخدمات (Kamatera.com أو Ionos.com أو ما شابه) ، ستحتاج إلى تسجيل الدخول. للقيام بذلك ، استخدم أمر SSH مع عنوان IP الخاص بك (العنوان هذا يبدو مثل xx.xx.xx.xx). ستحتاج أيضًا إلى أن تكون حساسة لاسم المستخدم الافتراضي على الخادم الذي أنشأناه ، على سبيل المثال ، Ubuntu.

ssh ubuntu@XX.XX.XX.XX
قد يُطلب منك كلمة مرور ، إذا طُلب منك كلمة مرور ، وأدخلها. لن نستخدم اسم المستخدم الافتراضي ، لذلك لنبدأ بإنشاء مستخدم جديد وإضافة مفتاح SSH إلى حسابه. لنبدأ بإضافة ملف SSHD_Config جديد ، والذي يخبر الخادم كيفية استخدام SSH.

nano sshd_config

# هذا هو ملف التكوين على مستوى نظام SSHD.  يرى
# SSHD_CONFIG (5) لمزيد من المعلومات.

# تم تجميع هذا SSHD باستخدام path =/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

# الاستراتيجية المستخدمة للخيارات في SSHD_CONFIG الافتراضية التي يتم شحنها مع
# Openssh هو تحديد الخيارات مع القيمة الافتراضية حيث
# ممكن ، لكن اتركهم علقوا.  الخيارات غير المعروفة تجاوز
# القيمة الافتراضية.

# الميناء 22
# addressfamily أي
# عنوان القائمة 0.0.0.0
# اسمع Adress ::

# HostKey/etc/ssh/ssh_host_rsa_key
# HostKey/etc/ssh/ssh_host_ecdsa_key
# HostKey/etc/ssh/ssh_host_ed25519_key

# الأصفار والمشاهدة
# rekeylimit الافتراضي لا شيء

# قطع الأشجار
# Syslogfacility Auth
# معلومات loglevel

# المصادقة:

# logringracetime 2m
# تصفح LOTROOTLOGIN
# الصارمة نعم
# Maxauthtristes 6
# الحد الأقصى 10

PubkeyAuthentication yes

# توقع .ssh/equalized_keys2 أن يتم تجاهله افتراضيًا في المستقبل.
AuthorizedKeysFile	.ssh/authorized_keys .ssh/authorized_keys2

# المعتمدة لا شيء

# AuthorizedKeyScommand لا شيء
# AuthorizedKyyScommanduser لا أحد

# لكي تعمل هذا ، ستحتاج أيضًا
# HostBasedAuthentication لا
# تغيير إلى نعم إذا كنت لا تثق
# HostBasedAuthentication
# تجاهل المعروف لا
# لا تقرأ ملفات المستخدم ~/.rhosts و ~/.shosts
# ignorerhosts نعم

# لتعطيل كلمات مرور نص واضحة ، قم بالتغيير إلى لا هنا!
PasswordAuthentication no
# permothempasspasswords لا

# التغيير إلى نعم لتمكين كلمات مرور التحدي والاستجابة (احذر مشكلات مع
# بعض وحدات PAM وخيوط)
KbdInteractiveAuthentication no

# خيارات Kerberos
# Kerberosauthentication لا
# kerberosorlocalpasswd نعم
# Kerberosticketcleanup نعم
# kerberoscotted قضيب لا

# خيارات GSSAPI
# GSSAPIAUTHENTICATION لا
# GSSAPICLEEANUPCREDENSTES نعم
# GSSapistrictAcceptorCheck نعم
# GSSAPIKEYEXCHANGE لا

# اضبط هذا على "نعم" لتمكين مصادقة PAM ، ومعالجة الحساب ،
# ومعالجة الجلسة. إذا تم تمكين هذا ، فإن مصادقة PAM سوف
# يُسمح به من خلال KBDINTACTIVEUTHENTICATICATION و
# passwordauthentication.  اعتمادًا على تكوين PAM الخاص بك ،
# مصادقة PAM عبر KBDINTERACTIVEUTHENTICATICATION قد تتجاوز
# إعداد "تصفح LOTROOTLOGIN بدون كلمة مرور".
# إذا كنت تريد فقط تشغيل حساب PAM وشيكات الجلسة بدون
# مصادقة PAM ، ثم قم بتمكين هذا ولكن تعيين كلمة مرور
# و KBDINTACTIVEATUTHENTICATION إلى "لا".
UsePAM yes

# السماح نعم نعم
# ALLESTCPFORDRADING YES
# Gatewayports لا
X11Forwarding yes
# x11displayoffset 10
# X11USELOCALHOST نعم
# حبوب منع الحمل نعم
PrintMotd no
# printlastlog نعم
# tcpkeepalive نعم
# perfertuenvironment في
# تأخر الضغط
# الفاصل الزمني العميل 0
# ClientAliveCountMax 3
# تستخدم في
# pidfile /run/sshd.pid
# MaxStartups 10: 30: 100
# pemittunl لا
# chrootdirectory لا شيء
# إصدار إضافة لا شيء

# لا يوجد مسار لافتة افتراضي
Banner /etc/banner

# السماح للعميل بتمرير متغيرات المتغيرات المحلية
AcceptEnv LANG LC_*

# تجاوز الافتراضي لعدم وجود أنظمة فرعية
Subsystem	sftp	/usr/lib/openssh/sftp-server

# مثال على الإعدادات الإفراط على أساس كل مستخدم
# مطابقة المستخدم anoncvs
# x11 forwarding لا
# ALLETTCPFORDRADING NO
# leftetty في
# خادم CVS Forcecommand
PermitRootLogin no
تذكر ، ctrl+x و y لحفظ الملف. بعد ذلك ، دعنا نكتب نصًا أساسيًا يسمى التهيئة (كل ذلك في الدليل الرئيسي الافتراضي لمستخدمنا).

nano initialize
أضف هذه الخطوط إلى الملف ، واستبدالهامع مفتاح SSH الخاص بك وجدته باستخدام CAT. (.ssh/id_rsa.pub)

# !
sudo apt install -y nano git openssh-server
sudo cp sshd_config /etc/ssh/sshd_config
sudo service ssh restart
sudo service sshd restart
echo "/root/.ssh/id_rsa" | sudo su root -c "ssh-keygen -t rsa -N ''"
echo "root ssh key:"
sudo su root -c "cat /root/.ssh/id_rsa.pub"
sudo adduser --disabled-password --gecos "" team
sudo passwd -d team
sudo usermod -aG sudo team
echo "/home/team/.ssh/id_rsa" | su team -c "ssh-keygen -t rsa -N ''"
cat /home/team/.ssh/id_rsa.pub >> /home/team/.ssh/authorized_keys
echo '<key here>' >> /home/team/.ssh/authorized_keys
echo "team ssh key:"
cat /home/team/.ssh/id_rsa.pub
للسير لك من خلال هذا الملف ، لنبدأ الخط حسب السطر. يخبر السطر الأول المترجم أن هذا نص باش. ثم نقوم بتثبيت التبعيات ، ونسخ SSHD_Config إلى الدليل الصحيح ، وإعادة تشغيل SSH ، وإنشاء مفاتيح SSH للجذر ، وإضافة "فريق" المستخدم (يمكنك اختيار اسم تريده لهذا ، واستخدام أمر AddUser مع اسمه وكلمة مرور تعطيله الآن). نضيف أيضًا فريقًا إلى مجموعة Sudo ، وننشئ مفتاح SSH الخاص بهم ، وإضافة مفتاحنا إلى المفاتيح المصرح بها ومواقعها ، وطباعة مفتاحها. سيكون هذا المستخدم الجديد هو كيفية تسجيل الدخول إلى الموقع. في محطة جديدة ، المضي قدما وافتح الخادم مرة أخرى.

ssh team@XX.XX.XX.XX
يجب ألا تحتاج إلى كلمة مرور هذه المرة ، حيث يكون لديك مفتاح SSH. قمنا أيضًا بتعطيل تسجيل الدخول بكلمة مرور لإبقاء الموقع أكثر أمانًا. الآن ، يبدأ هذا الخادم فارغًا تمامًا بدون معلومات عليه. لنبدأ من خلال استنساخ مشروعنا من GIT حتى نتمكن من تنزيله وتشغيله على الجهاز البعيد. على الخادم البعيد المتصل عبر SSH ، قم أولاً بطباعة مفتاح SSH الخاص بك:

cat ~/.ssh/id_rsa.pub
بعد ذلك ، قم بصق هذا المفتاح في إعدادات GIT كما فعلنا من قبل لإعداد مستودع GIT الخاص بنا. قد نقوم الآن باستنساخ مشروعنا مباشرة إلى الخادم. تأكد من قيامك بنسخة احتياطية من المشروع محليًا أولاً ، لذا فهو على خادم GIT للتنزيل.

git clone git://github.com/you/yourproject.git
ممتاز. الآن جميع الملفات هنا. يمكننا أن نراهم مع LS

ls
الآن ، لنبدأ في إعداد الخادم. أولاً ، انسخ دليل المشروع الخاص بك إلى اسم بسيط لا يُنسى سنستخدمه للمشروع.

cp -r yourproject whatyoucalledit
حيث "WhatoUcalledit" هو الاسم الجديد لمشروعك. بعد ذلك ، سنحتاج إلى إنشاء أداة أساسية لإعداد الخادم. سنوفر هذه الأداة ونستخدمها في المستقبل. لبناء هذه الأداة المساعدة ، دعنا ننشئ مستخدمًا ثنائيًا لتحديد كيفية تحرير البرنامج النصي. باستخدام bash ، تحرير/usr/bin/ascript

sudo nano /usr/bin/ascript
تأكد من استخدام Sudo هناك حتى يكون لديك أذونات لتحرير الملف. في الملف ، أضف هذه الأسطر:

# !
if [ ! -f /usr/bin/$1 ]; then
    sudo touch /usr/bin/$1
    echo "# ! / bin / bash
    sudo chmod a+x /usr/bin/$1
    sudo nano /usr/bin/$1
    echo $1 | sudo tee -a /etc/ascripts
else
    sudo chmod a+x /usr/bin/$1
    sudo nano /usr/bin/$1
fi
تذكر أن هذا البرنامج النصي يأخذ وسيطة ، اسم البرنامج النصي ، بمبلغ 1 دولار. أولاً ، يتحقق ما إذا كان الملف موجودًا ، أو ينشئه بطريقة أخرى ، يضيف السطر الأول لإعلان أن البرنامج النصي هو bash ، ويغير أذوناته ، ويقوم بتحريره ، ويضيف اسمه إلى /etc /ascripts مما يتيح لنا تخزين أسماء البرامج النصية يخلقون. إذا كان الملف موجودًا بالفعل ، فما عليك سوى تغيير الأذونات وتحريره. احفظ الملف ، وبعد ذلك سنقوم بتغيير أذوناته. طالما أننا نستخدم هذا البرنامج النصي ، فلن نضطر إلى القيام بذلك مرة أخرى.

sudo chmod a+x /usr/bin/ascript
ممتاز. الآن دعنا ننشئ برنامج نصي يسمى الإعداد. أولاً ، لا تطغى عليك ، ولكن ألقِ نظرة على الشكل الذي يبدو عليه نص الإعداد. سوف نسير عبر شكل هذا البرنامج النصي في مشروعك ، فلن تحتاج إلى كل شيء في البرنامج النصي لتبدأ به.

# !/بن/باش
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
# sudo chmod a+x scripts/usereSetup
# ./scripts/usersetup
# ssh-keyen
# دليل المشروع
DIR="/home/team/femmebabe"
USER="team"
# أوامر السجل
echo "Logging commands"
sudo cp log/commands.log /var/log/commands.log
sudo chmod -R a+w /var/log
sudo chown -R :syslog /var/log
echo $'alias venv="source /home/team/femmebabe/venv/bin/activate"' | sudo tee -a /home/team/.profile
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a /etc/bashrc
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a "/home/team/.bashrc"
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a /root/.bashrc
echo "source /etc/bashrc" | sudo tee -a /home/team/.profile
echo "/var/log/commands.log" | sudo tee -a /etc/logrotate.d/syslog
echo "local6.*    /var/log/commands.log" | sudo tee -a "/etc/rsyslog.d/bash.conf"
sudo service rsyslog restart
# تكوين النانو
echo "set tabsize 4" >> .nanorc
echo "set tabstospaces" >> .nanorc
# GIT التكوين
echo "Git configuration"
sudo git config --global user.email "jasper.camber.holton@gmail.com" && sudo git config --global user.name "Jasper Holton"
git config --global user.email "jasper.camber.holton@gmail.com"
git config --global user.name "Jasper Holton"
git config --global --add safe.directory $"$DIR"
sudo ssh-keyscan -t rsa gitlab.com | sudo tee -a /root/.ssh/known_hosts
sudo ssh-keyscan -t rsa github.com | sudo tee -a /root/.ssh/known_hosts
echo "Mounting setup"
sudo mount -o remount,size=16G,exec /tmp
# تحديث وتثبيت
echo "Update and install packages"
sudo apt update && sudo NEEDRESTART_MODE=a apt upgrade -y
sudo apt purge postgresql-client-14 postgresql-client-common postgresql-common postgresql-contrib postgresql -y
echo "postfix postfix/mailname string femmebabe.com" | sudo debconf-set-selections
echo "postfix postfix/main_mailer_type string 'Internet Site'" | sudo debconf-set-selections
sudo NEEDRESTART_MODE=a DEBIAN_FRONTEND=noninteractive apt install -y postfix
sudo NEEDRESTART_MODE=a apt install -y rkhunter clamav-daemon libx264-dev ffmpeg libapache2-mod-wsgi-py3 apache2 cmake python-is-python3 python3-venv python3-pip python3-django expect tesseract-ocr openjdk-8-jdk redis-server libopencv-dev python3-opencv python3-dev libsasl2-dev opendkim opendkim-tools dovecot-core dovecot-pop3d dovecot-imapd auditd procmail libpq-dev postgresql postgresql-contrib libheif-dev snapd git software-properties-common certbot python3-certbot-apache
echo "-a exit,always -F arch=b64 -F euid=0 -S execve" | sudo tee -a /etc/audit/audit.rules
echo "-a exit,always -F arch=b32 -F euid=0 -S execve" | sudo tee -a /etc/audit/audit.rules
# تمكين Clamav مكافحة الفيروسات
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# تعيين اسم المضيف
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname localhost
# الإعداد postgres
echo "Postgres setup"
sudo -u postgres psql -U postgres -c "DROP DATABASE database;"
sudo -u postgres psql -U postgres -c "CREATE DATABASE database;"
sudo -u postgres psql -U postgres -c "CREATE USER django WITH PASSWORD 'password';"
sudo -u postgres psql -U postgres -c "ALTER ROLE django SET client_encoding TO 'utf8';"
sudo -u postgres psql -U postgres -c "ALTER ROLE django SET default_transaction_isolation TO 'read committed';"
sudo -u postgres psql -U postgres -c "ALTER ROLE django SET timezone TO 'UTC';"
sudo -u postgres psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE database TO django;"
# إعداد قاعدة بيانات النسخ الاحتياطي
echo "Building database from backup, this may take a while."
cat db.json.?? > db.json
echo "Configuring firewall"
sudo ufw default allow outgoing
sudo ufw default deny incoming
sudo ufw allow 22
sudo ufw allow http
sudo ufw allow https
sudo ufw allow 'Postfix'
sudo ufw allow 'Postfix SMTPS'
sudo ufw allow 'Postfix Submission'
sudo ufw allow 'Dovecot POP3'
sudo ufw allow 'Dovecot Secure POP3'
sudo ufw allow 110/tcp
sudo ufw allow 25/tcp
echo "y" | sudo ufw enable
# Ipatables المعوقين
echo "Configuring firewall"
sudo iptables -P INPUT ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -F
sudo iptables-save
# تثبيت bitdefender
cd $DIR
echo "Runnning BitDefender antivirus installer"
wget https://cloud.gravityzone.bitdefender.com/Packages/NIX/0/7aTSsy/setup_downloader.tar
mkdir bitdefender
tar -xf setup_downloader.tar -C bitdefender
sudo rm setup_downloader.tar
sed -i -e 's/{LOGINPASSWD/z&A*3BPd_qBGUMs/g' bitdefender/installer
sudo chmod a+x bitdefender/installer
sudo ./bitdefender/installer
# إعداد postfix
cd $DIR
echo "Mail services configuration"
sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.backup
sudo cp config/etc_postfix_main.cf /etc/postfix/main.cf
sudo cp config/etc_postfix_master.cf /etc/postfix/master.cf
sudo cp config/etc_default_opendkim /etc/default/opendkim
sudo cp config/etc_dovecot_conf.d_10-auth.conf /etc/dovecot/conf.d/10-auth.conf
sudo cp config/etc_dovecot_conf.d_10-master.conf /etc/dovecot/conf.d/10-master.conf
sudo cp config/etc_dovecot_dovecot.conf /etc/dovecot/dovecot.conf
sudo cp config/etc_dovecot_passwd /etc/dovecot/passwd
sudo cp config/etc_opendkim.conf /etc/opendkim.conf
sudo cp config/etc_default_opendkim /etc/default/opendkim
sudo adduser postfix opendkim
sudo mkdir /etc/opendkim
sudo mkdir /etc/opendkim/keys
sudo mkdir /etc/opendkim/keys/femmebabe.com
sudo mkdir /var/spool/postfix/opendkim
sudo echo "*@femmebabe.com     sendonly._domainkey.femmebabe.com" | sudo tee -a /etc/opendkim/signing.table
sudo echo "sendonly._domainkey.femmebabe.com    femmebabe.com:sendonly:/etc/opendkim/keys/femmebabe.com/sendonly.private" | sudo tee -a /etc/opendkim/key.table
sudo echo "127.0.0.1" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "localhost" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "*.femmebabe.com" | sudo tee -a /etc/opendkim/trusted.hosts
sudo chown -R opendkim:opendkim /etc/opendkim
sudo opendkim-genkey -b 2048 -d femmebabe.com -D /etc/opendkim/keys/femmebabe.com -s sendonly -v
sudo chmod go-rw /etc/opendkim/keys
sudo chown opendkim:opendkim /etc/opendkim/keys/femmebabe.com/sendonly.private
sudo chown opendkim:postfix /var/spool/postfix/opendkim
cd $DIR
sudo cp mailbox/* /var/mail/
sudo chown :users /var/mail/*
sudo chmod -R a+rwx /var/mail/*
sudo systemctl restart opendkim postfix dovecot
# إنشاء dirs
cd $DIR
mkdir media/audio
mkdir media/audio/fingerprints
mkdir media/security
mkdir media/secure
mkdir media/secure/media
mkdir media/secure/video
mkdir media/secure/profile
mkdir media/secure/face
mkdir media/images
mkdir media/live
mkdir media/live/files
mkdir media/live/stills
mkdir media/files
mkdir temp
mkdir temp/data
mkdir temp/gfpgan
mkdir mail/inbox
mkdir mailbox
# إعداد Virtuealenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
# احصل على تبعيات وبناء
echo "Getting and building dependencies, this may take a whike"
cd $DIR
git clone https://github.com/sukhitashvili/violence-detection.git
cp config/vd-requirements.txt violence-detection/requirements.txt
cp config/vd-model.py violence-detection/model.py
cd violence-detection
pip3 install -r requirements.txt
cd $DIR
wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth -P experiments/pretrained_models
git clone https://github.com/TencentARC/GFPGAN.git
git clone https://github.com/davisking/dlib.git
cd dlib
mkdir build; cd build; cmake ..; cmake --build .
cd ..
source venv/bin/activate
python setup.py install
cd $DIR
source venv/bin/activate
cd $DIR/GFPGAN/
echo "Installing python dependencies"
pip install basicsr
pip install facexlib
pip install -r requirements.txt
python setup.py develop
pip install realesrgan
cd $DIR
sudo chown -R team:users gfpgan
echo "Installing ta-lib"
wget https://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
tar xvzf ta-lib-0.4.0-src.tar.gz
sudo rm ta-lib-*
cd ta-lib
sudo ./configure
sudo make
sudo make install
# تعيين قواعد جدار الحماية
cd $DIR
# تثبيت تبعيات PYPI
echo "Installing remaining python dependencies (this may take a while)"
sudo systemctl mask tmp.mount
cd $DIR
source venv/bin/activate
pip3 install -U "celery[redis]"
pip3 install -r requirements.txt --use-deprecated=legacy-resolver --use-pep517
pip3 install --upgrade opencv-python # == 4.5.4.60
pip3 install --upgrade opencv-contrib-python # == 4.5.4.60
# PIP تثبيت OpenCV-Python == 4.5.5.64
# PIP تثبيت OpenCV-Contrib-Python == 4.5.5.64
pip3 install --upgrade opencv-python-headless
pip3 uninstall channels
pip3 uninstall daphne
pip3 install channels["daphne"]
pip3 install Pillow==9.5.0
pip3 install librosa
pip3 install -U 'Twisted[tls,http2]'
pip3 install --upgrade certifi requests urllib3 numpy oauthlib twisted pyjwt sqlparse cryptography astral webauthn docbarcodes pdf417 deepface --no-cache-dir
pip3 install tensorflow==2.15.1
# تثبيت certbot
echo "Installing certificates"
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo snap install redis
sudo systemctl enable apache2
sudo systemctl start apache2
# تشغيل certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email jasper.camber.holton@gmail.com
# خادم البريد إعادة تحميل
sudo systemctl restart opendkim postfix dovecot
# نسخ certs
# sudo cp /etc/letsencrypt/live/femmebabe.com/privkey.pem privkey.pem
# sudo cp /etc/lettesencrypt/live/femmebabe.com/cert.pem cert.pem
# رقعة
cp scripts/content.py $"/home/team/femmebabe/venv/lib/python${PYTHON_VERSION}/site-packages/pyxb/binding/content.py"
cp scripts/pwa_webpush_forms.py $"/home/team/femmebabe/venv/lib/python${PYTHON_VERSION}/site-packages/pwa_webpush/forms.py"
cp scripts/webauth_views.py $"/home/team/femmebabe/venv/lib/python${PYTHON_VERSION}/site-packages/webauth/views.py"
cp scripts/json.py $"venv/lib/python${PYTHON_VERSION}/site-packages/django/core/serializers/json.py"
# تعيين إعدادات المستخدم
sudo gpasswd -a www-data users
# تعيين أذونات
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# Sudo Chown -r Team: المستخدمون/var/run/
# جذر Sudo Chown: Root/Run/Sudo/TS -r
sudo chown -R redis:redis /var/lib/redis
sudo chown -R redis:redis /var/log/redis
sudo chmod -R u+rwX,g+rwX,u+rx /var/log/redis
sudo chmod +r /etc/redis/redis.conf
sudo chown -R team:users /var/log/
sudo chown -R :users .././
sudo chmod -R g+rwX ./
sudo chmod -R g+rX .././
sudo chmod -R g-rwX ../.ssh
sudo chmod 774 ./
# sudo chmod 664 db.sqlite3
# sudo chown www-data: المستخدمون db.sqlite3
sudo chown -R www-data:www-data media/
sudo chown www-data:users ./
sudo chown -R team:users media/
sudo chown -R team:users ./
sudo chown -R team:users ./gfpgan/
sudo chown -R team:users ./temp/
sudo chmod a+r team /var/mail/$USER
# نسخ الأذونات وضبط الأذونات
echo "Configuring remaining services"
sudo cp config/apis.json /etc/apis.json
sudo cp config/config.json /etc/config.json
sudo cp config/femmebabe-le-ssl.conf /etc/apache2/sites-available/femmebabe-le-ssl.conf
sudo cp config/etc_dovecot_passwd /etc/dovecot/passwd
sudo cp config/etc_init.d_celery /etc/init.d/celery
sudo cp config/etc_init.d_celerybeat /etc/init.d/celerybeat
sudo cp config/etc_default_celerybeat /etc/default/celerybeat
sudo cp config/etc_default_celery /etc/default/celery
sudo cp config/etc_systemd_system_daphne.service /etc/systemd/system/daphne.service
sudo cp config/etc_systemd_system_celery.service /etc/systemd/system/celery.service
sudo cp config/etc_systemd_system_celerybeat.service /etc/systemd/system/celerybeat.service
sudo chmod a+x /etc/init.d/celery
sudo chmod a+x /etc/init.d/celerybeat
# إعداد قاعدة البيانات
echo "Running migrations, this should be quick"
python manage.py makemigrations
python manage.py migrate --run-syncdb
echo "Loading data, this may take a while"
python manage.py loaddata db.json
echo "Setup crontab/sudoers configuration"
sudo crontab -l -u root | cat - config/crontab | sudo crontab -u root -
sudo sh -c "cat config/sudoers >> /etc/sudoers"
# حقن تكوين PAM وإزالة تكوين SSH المعيب
# sudo sed -i '' -e '$ d' /tc/pam.d/sshd
# sudo sed -i '' -و $ d ' /etc /profile
echo "session required pam_exec.so seteuid /home/team/femmebabe/pam.sh" | sudo tee -a /etc/pam.d/sshd
echo "session required pam_exec.so seteuid /home/team/femmebabe/logout.sh" | sudo tee -a /etc/pam.d/sshd
sudo chmod a+x pam.sh
sudo rm /etc/ssh/sshd_config.d/50-cloud-init.conf
# نسخ البرامج النصية بن وضبط الأذونات
echo "Copying scripts"
sudo cp scripts/reload /usr/bin/
sudo cp scripts/check /usr/bin/
sudo cp scripts/enagpu /usr/bin/
sudo cp scripts/disgpu /usr/bin/
sudo cp scripts/activate /usr/bin/
sudo cp scripts/backup /usr/bin/
sudo cp scripts/ascript /usr/bin/
sudo cp scripts/setup /usr/bin/
sudo cp scripts/addsetup /usr/bin/
sudo cp scripts/watchlogs /usr/bin/
sudo cp scripts/logs /usr/bin/
sudo cp scripts/cmds /usr/bin/
sudo cp scripts/setup /usr/bin/
sudo cp scripts/pushweb /usr/bin/
sudo cp scripts/purgecache /usr/bin/
sudo cp config/banner /etc/banner
cd /usr/bin/
sudo chmod a+x activate
sudo chmod a+x backup
sudo chmod a+x ascript
# إعادة تحميل وتمكين الخدمات
echo "Enabling services"
sudo systemctl daemon-reload
sudo systemctl enable daphne.service
sudo systemctl enable celery.service
sudo systemctl enable celerybeat.service
sudo systemctl enable clamav-daemon
sudo systemctl start daphne.service
sudo systemctl start celery.service
sudo systemctl start celerybeat.service
sudo systemctl start clamav-daemon
# تمكين وحدات Apache
echo "Enabling apache2"
sudo a2enmod rewrite
sudo a2enmod wsgi
sudo a2enmod headers
sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_balancer
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
# sudo a2dismod mpm_event
# sudo a2dismod mpm_worker
# sudo a2enmod mpm_prefork
# تعطيل الموقع الافتراضي
sudo a2dissite 000-default
sudo a2dissite 000-default-le-ssl
# تمكين الموقع
sudo a2ensite femmebabe-le-ssl
# إعادة تحميل الخفي وإعادة تشغيل Apache و Postfix و Opendkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
sudo systemctl start daphne
# تعيين أذونات
sudo chown -R :www-data /var/www/
sudo chown -R :www-data /var/www/.deepface
# تبديل التكوين
echo "Allocating swap, this may take a while"
sudo swapoff /swapfile
sudo rm /swapfile
sudo fallocate -l 8G /swapfile
sudo dd if=/dev/zero of=/swapfile bs=1024 count=8388608
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo "/swapfile swap swap defaults 0 0" | sudo tee -a /etc/fstab
sudo swapon --show
# محرك التسمية التوضيحية
echo "Initializing routine caption"
/home/team/femmebabe/venv/bin/python /home/team/femmebabe/routine_caption.py
/home/team/femmebabe/venv/bin/python /home/team/femmebabe/setup_mail.py
# إعداد git
echo "Setting up git"
cd $DIR
sudo rm -r .git
git init --initial-branch=main
echo "Setting user password"
sudo usermod --password $(echo team | openssl passwd -1 -stdin) team
# عرض IPv6 و OpendKim لتكوين المجال
echo "COPY the below information to domain configuration."
hostname -I
ip a | grep inet
ip -6 addr | grep "scope link"
sudo cat /etc/opendkim/keys/femmebabe.com/sendonly.txt | tr -d '\n' | sed 's/\s//g' | sed 's/""//g' | awk -F'[)(]' '{print $2}'
# الانتهاء من الإعداد
echo "Setup completed in"
wc -l scripts/setup
echo "lines of code."
echo "Total time:"
duration=$SECONDS
echo "$((duration / 60)) minutes and $((duration % 60)) seconds elapsed."
echo "TODO:"
echo "- COPY above IPv6 address to domain DNS configuration"
echo "- COPY domain key to domain DNS configuration"
echo "- ADD new git repository with git remote add originlab <repo>."
echo "- OPEN port 25"
echo "- INSTALL antivirus as per reccomendations"
echo "- TEST"
echo "If neccesary,"
echo "- DEBUG"
echo "- FIX setup and backup scripts"
echo "- Fix server"
echo ""
echo "Thank you for using the femmebabe installer. Have a great day!"
echo "Goodbye."
هذا كثير من الإعداد! باختصار ، يقوم هذا الرمز بتسجيل الأوامر ، ويقوم بتكوين nano و git ، والنسخ على الملفات ، والتنزيلات وتثبيت حزم Ubuntu APT ، وتبعيات python ، وتكوين postfix ، وتكوين postgresql (خادم قاعدة البيانات) ويقوم بتحميل قاعدة البيانات ، وتكوين ufw (حارس حماية غير معقد) ، يعطل Iptables ، ويقوم بتنزيل مكافحة الفيروسات ، ويصنع الدلائل ، وتبعيات الحيوانات المستنسخة ، وتثبيت الشهادات وإعداد الخادم ، ويقوم بتثبيت التكوين ، ويبدأ ويمكّن من SEVER ، ويخصص المبادلة ، ويضع أذونات ، ويطبع عنوان IP و IPv6 ومفتاح OpendKim. بسيط إلى حد ما ، لكنه يبدو وكأنه الكثير من التعليمات البرمجية. لن نحتاج إلى الكثير من هذا لأننا لا نمتلك التبعيات ، فنحن لا نستخدم الكرفس أو الكرفس أو Daphne ، لكننا سنقوم بتثبيت بعضها على أي حال للبدء. لاحظ أن هذا الرمز له مجال تم إعلانه عدة مرات. سنحتاج أيضًا إلى شراء اسم مجال (وهو رسوم سنوية صغيرة). أوصي Squarespace لشراء مجال ، تخطيطهم هوبديهية وسهلة الاستخدام. يمكنك شراء أي مجال من اختيارك ، لكنني أستخدم Domain Femmebabe.com في هذا المثال. بمجرد شراء مجال ، توجه إلى لوحة تكوين Squarespace DNS وإضافة سجل يشير إلى نطاقك إلى الخادم حسب عنوان IP. يجب أن يبدو هكذا: @ A xx.xx.xx.xx مع تشغيل المشغل كمضيف ، بمعنى أن جميع النطاقات الفرعية تحت هذا المجال وستعيد كل المجال الجذر إلى الخادم. هناك المزيد من السجلات التي يجب إعلانها ، ولكن يمكننا الانتقال إلى هذه بمجرد أن نكون مستعدين لإرسال البريد. ضع في اعتبارك ، قد يستغرق الأمر عدة أيام قبل أن تتمكن من إرسال البريد بنجاح من الخادم. سوف تستغرق سجلات DNS التي نضعها وقتًا للانتشار. على أي حال ، فإن السجل الوحيد الذي نحتاج للبدء هو سجل. حتى الآن يمكننا ملء البرنامج النصي أدناه وفقًا لمشروعنا وتشغيله. لنبدأ بنصوص إعداد أصغر لتثبيت ما نحتاجه لتقدم أساسي. لن نستخدم الكثير من التبعيات أو postgreSQL حتى الآن ، سنقوم فقطحتى خادم HTTP الأساسي والقلق بشأن التصديق عليه عندما يتم ذلك. تذكر ، للحصول على شهادة HTTPS وتشغيل الخادم بشكل آمن ، سنحتاج إلى شراء مجال مع استئجار خادم. في الوقت الحالي ، استبدل "Team" في هذا الملف باسم المستخدم الخاص بك ، و "DIR" مع دليل مشروعك ، وقم بتزويد بريدك الإلكتروني والمجال في علامات <>. بالإضافة إلى ذلك ، قبل تشغيل هذا الرمز ، نحتاج إلى تغيير الإعدادات إلى جدار الحماية الذي يدعمه مزود الاستضافة ، إن وجد. عادةً ما يكون هذا في علامة التبويب "الشبكات" لمزود الاستضافة الخاص بك ، أو إذا كنت تستضيف ذاتيًا ، فهو في قسم "إعادة توجيه المنفذ" في جهاز التوجيه الخاص بك. ستحتاج أيضًا إلى إعداد IP ثابت من خلال جهاز التوجيه الخاص بك مع عنوان جهاز الخادم الخاص بك ، إذا كنت تستخدم الاستضافة الذاتية. ستحتاج إلى فتح المنافذ التالية للوصول إلى القراءة/الكتابة. 22 (SSH) 25 (البريد) 587 (البريد) 110 (عميل البريد) 80 (HTTP) 443

# !
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
DIR="/home/team/<yourproject>"
USER="team"
# أوامر السجل
echo "Logging commands"
sudo cp log/commands.log /var/log/commands.log
sudo chmod -R a+w /var/log
sudo chown -R :syslog /var/log
echo $'alias venv="source /home/team/femmebabe/venv/bin/activate"' | sudo tee -a /home/team/.profile
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a /etc/bashrc
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a "/home/team/.bashrc"
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a /root/.bashrc
echo "source /etc/bashrc" | sudo tee -a /home/team/.profile
echo "/var/log/commands.log" | sudo tee -a /etc/logrotate.d/syslog
echo "local6.*    /var/log/commands.log" | sudo tee -a "/etc/rsyslog.d/bash.conf"
sudo service rsyslog restart
# تكوين النانو
echo "set tabsize 4" >> .nanorc
echo "set tabstospaces" >> .nanorc
# GIT التكوين
echo "Git configuration"
sudo git config --global user.email "<youremail>@gmail.com" && sudo git config --global user.name "<yourname>"
git config --global --add safe.directory $"$DIR"
sudo ssh-keyscan -t rsa gitlab.com | sudo tee -a /root/.ssh/known_hosts
sudo ssh-keyscan -t rsa github.com | sudo tee -a /root/.ssh/known_hosts
# تحديث وتثبيت
echo "Update and install packages"
sudo apt update && sudo NEEDRESTART_MODE=a apt upgrade -y
sudo apt purge postgresql-client-14 postgresql-client-common postgresql-common postgresql-contrib postgresql -y
echo "postfix postfix/mailname string femmebabe.com" | sudo debconf-set-selections
echo "postfix postfix/main_mailer_type string 'Internet Site'" | sudo debconf-set-selections
sudo NEEDRESTART_MODE=a DEBIAN_FRONTEND=noninteractive apt install -y postfix
sudo NEEDRESTART_MODE=a apt install -y rkhunter clamav-daemon libx264-dev ffmpeg libapache2-mod-wsgi-py3 apache2 cmake python-is-python3 python3-venv python3-pip python3-django expect tesseract-ocr openjdk-8-jdk redis-server libopencv-dev python3-opencv python3-dev libsasl2-dev opendkim opendkim-tools dovecot-core dovecot-pop3d dovecot-imapd auditd procmail libpq-dev postgresql postgresql-contrib libheif-dev snapd git software-properties-common certbot python3-certbot-apache
# تمكين Clamav مكافحة الفيروسات
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# تعيين اسم المضيف
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname femmebabe
# إعداد قاعدة بيانات النسخ الاحتياطي
echo "Building database from backup, this may take a while."
cat db.json.?? > db.json
echo "Configuring firewall"
sudo ufw default allow outgoing
sudo ufw default deny incoming
sudo ufw allow 22
sudo ufw allow http
sudo ufw allow https
sudo ufw allow 'Postfix'
sudo ufw allow 'Postfix SMTPS'
sudo ufw allow 'Postfix Submission'
sudo ufw allow 'Dovecot POP3'
sudo ufw allow 'Dovecot Secure POP3'
sudo ufw allow 110/tcp
sudo ufw allow 25/tcp
echo "y" | sudo ufw enable
# Ipatables المعوقين
echo "Configuring firewall"
sudo iptables -P INPUT ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -F
sudo iptables-save
# إعداد Virtuealenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
pip3 install -r requirements.txt
# تثبيت certbot
echo "Installing certificates"
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo snap install redis
sudo systemctl enable apache2
sudo systemctl start apache2
# تشغيل certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email <youremail>@gmail.com
# تعيين إعدادات المستخدم
sudo gpasswd -a www-data users
# تعيين أذونات
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# Sudo Chown -r Team: المستخدمون/var/run/
# جذر Sudo Chown: Root/Run/Sudo/TS -r
sudo chown -R redis:redis /var/lib/redis
sudo chown -R redis:redis /var/log/redis
sudo chmod -R u+rwX,g+rwX,u+rx /var/log/redis
sudo chmod +r /etc/redis/redis.conf
sudo chown -R team:users /var/log/
sudo chown -R :users .././
sudo chmod -R g+rwX ./
sudo chmod -R g+rX .././
sudo chmod -R g-rwX ../.ssh
sudo chmod 774 ./
sudo chown -R www-data:www-data media/
sudo chown www-data:users ./
sudo chown -R team:users media/
sudo chown -R team:users ./
# إعادة تحميل وتمكين الخدمات
echo "Enabling services"
sudo systemctl daemon-reload
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# تمكين وحدات Apache
echo "Enabling apache2"
sudo a2enmod rewrite
sudo a2enmod wsgi
sudo a2enmod headers
sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_balancer
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
# إعادة تحميل الخفي وإعادة تشغيل Apache و Postfix و Opendkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
# عرض IPv6 و OpendKim لتكوين المجال
echo "COPY the below information to domain configuration."
hostname -I
ip a | grep inet
ip -6 addr | grep "scope link"
قبل تشغيل هذا الرمز ، تأكد من توصيل المجال الذي اشتريته بالخادم. للقيام بذلك ، افتح محطة على جهازك المحلي ، وقم بتشغيل هذا الأمر مع مجالك:

ping femmebabe.com # أدخل مجالك هنا ، بعد Ping
إذا كان كل شيء يبدو جيدًا وأرسل الخادم ردود ، فنحن على استعداد لتشغيل البرنامج النصي وتثبيت الحزم بالإضافة إلى بدء وتمكين وتصديق خادم Apache الخاص بنا. هذا ليس كل الإعدادات اللازمة لتكوين Postfix ، وسننظر في هذا الإعداد لاحقًا. في الوقت الحالي ، قم بتشغيل رمز الإعداد هذا ، ويجب أن يستغرق الأمر بضع دقائق لتثبيت الخادم الخاص بك. مرة أخرى ، تأكد من استبدال الاسم والبريد الإلكتروني واسم المجال في البرنامج النصي وفقًا للاسم الذي اشتريته. الآن بعد توفير الخادم ، يمكنك الانتقال إلى عنوان URL في أي متصفح ويب والتحقق للتأكد من تشغيل الخادم HTTPS. إذا لم يكن الأمر كذلك ، فحاول الانتظار قليلاً حتى يتم اللحاق بسجلات DNS ثم تشغيل الأمر التالي لإعادة إنشاء شهادة CertBot:

sudo certbot --apache --non-interactive --agree-tos --domains <domain>.com --email <youremail>@gmail.com
طالما قمت بتكوين كل شيء بشكل صحيح ، فيجب أن تكون قادرًا على الوصول إلى صفحة Apache الافتراضية فقط لمعرفة رمزك يعمل وعرض صفحة ويب حية. بعد ذلك ، دعنا نقوم بتحرير الإعدادات. قم بتغيير وضع التصحيح الافتراضي الخاص بنا إلى الإنتاج. سنقوم أيضًا بتكوين المجال في الإعدادات ، وكذلك IPS الداخلية.

nano yourproject/settings.py
في الإعدادات ، قم بتغيير/إضافة هذه الخطوط.

DEBUG = False

# تكوين الموقع
SITE_NAME = 'Femme Babe'
PROTOCOL = 'https'
DOMAIN = 'femmebabe.com'
SITE_ID = 1
BASE_URL = PROTOCOL + '://' + DOMAIN
ALLOWED_HOSTS = [DOMAIN]

INTERNAL_IPS = [
    'XX.XX.XX.XX',
]
الآن ، سنحتاج إلى تكوين Apache2. دعنا نقوم بتحرير ملف التكوين الذي سننشره مع هذا السطر:

sudo nano /etc/apache2/sites-available/femmebabe-le-ssl.conf
يجب أن يكون لهذا ملف التكوين اسم المجال لدينا فيه ، واسم المستخدم والمشروع. أنا أستخدم اسم المجال FemmeBabe.com ، وفريق اسم المستخدم ، واسم المشروع Femmebabe.

ServerSignature Off
ServerTokens Prod
<IfModule mod_ssl.c>
<VirtualHost *:80> 
	Redirect permanent / https://femmebabe.com/
</VirtualHost>
<VirtualHost *:443>
	ServerName femmebabe.com
	ServerAdmin team@femmebabe.com
	DocumentRoot /var/www/html

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined
	
	Alias /static /home/team/femmebabe/static
	<Directory /home/team/femmebabe/static>
		Require all granted
	</Directory>

Alias /media/icons /home/team/femmebabe/media/
<Directory /home/team/femmebabe/media>
Require all granted
</Directory>

	<Directory /home/team/femmebabe/femmebabe>
		<Files wsgi.py>
			Require all granted
		</Files>
	</Directory>

	WSGIScriptAlias / /home/team/femmebabe/femmebabe/wsgi.py
	WSGIDaemonProcess femmebabe python-path=/home/team/femmebabe/ python-home=/home/team/femmebabe/venv header-buffer-size=100000000000 user=team
	WSGIProcessGroup femmebabe
	WSGIApplicationGroup %{GLOBAL}
	
	<Directory /home/team/femmebabe/static>
                Options Indexes FollowSymLinks
                AllowOverride All
	</Directory>

	<IfModule mod_rewrite.c>
		RewriteEngine on
		RewriteCond %{REQUEST_URI} \.(css|webp|webm|gif|png|mp3|wav|jpeg|jpg|svg|webp)$ [NC]
		RewriteCond %{HTTP_REFERER} !^https://femmebabe.com/media/.*$ [NC]
		RewriteRule ^(.+?)/$ /media/$1 [F,L]
	</IfModule>

	Include /etc/letsencrypt/options-ssl-apache.conf
	SSLCertificateFile /etc/letsencrypt/live/femmebabe.com/fullchain.pem
	SSLCertificateKeyFile /etc/letsencrypt/live/femmebabe.com/privkey.pem

	Header set X-Frame-Options: "SAMEORIGIN"
	Header set Access-Control-Allow-Origin "https://femmebabe.com"

	TimeOut 60000
	LimitRequestBody 0

	<FilesMatch ".(ico|pdf|flv|jpg|jpeg|png|gif|webp|JPG|JPEG|wav|mp3|mp4|public|js|css|swf|webp|svg)$">
		Header set Cache-Control "max-age=30, public"
	</FilesMatch>
</VirtualHost>
</IfModule>
<IfModule mod_ssl.c>
<VirtualHost *:80>
	ServerName femmebabe.com
	ServerAdmin team@femmebabe.com
	DocumentRoot /var/www/html

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

	RewriteEngine on
	RewriteCond %{SERVER_NAME} =femmebabe.com
	RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
</IfModule>
تأكد من استبدال اسم المشروع ، الدلائل ، والمجال في رمز هذا المثال عند تكوين الخادم الخاص بك. الآن ، سنحتاج إلى تعطيل الموقع الافتراضي. يمكن القيام بذلك باستخدام باش.

sudo a2dissite 000-default-le-ssl
sudo a2dissite 000-default
sudo a2dissite default-ssl
بعد ذلك ، يمكننا تمكين الموقع الافتراضي وإعادة تحميل Apache2 ، باستخدام Bash. تذكر أن تحل محل FemmeBabe باسم الملف الذي أعلنته عند التحرير في/etc/apache2/sites-

sudo a2ensite femmebabe-le-ssl
sudo systemctl reload apache2
ارجع إلى مجالك في Navbar. يجب أن ترى الموقع الذي قمت بتكوينه في متصفح الويب الخاص بك. مبروك! إذا لم تراها ، فقد تحتاج إلى إجراء بعض التغييرات. مراجعة الإعدادات في مشروعك بعناية ، وتكوين Apache ، وتأكد من عدم وجود أي أخطاء ، وقم بتشغيل الأوامر التالية للتحقق من المشروع بحثًا عن الأخطاء.

cd projectname
source venv/bin/activate
python manage.py check
إذا كانت لديك أخطاء في مشروع Python الخاص بك ، فقم بتتبعها إلى مكانهم وإصلاحها. قد لا تكون قادرًا على رؤية جميع أخطائك اعتمادًا على مكان وجودها ، لذلك إذا كان لديك خطأ يقول ببساطة "Populate ليس reentrant" ، قم بتحرير الملف التالي في البيئة الافتراضية ، registry.py ، لفضح خطأ.

nano venv/lib/python3.12/site-packages/django/apps/registry.py
قم بالتمرير إلى السطر 83 ، حيث يتم رفع خطأ وقت التشغيل هذا (رفع وقت التشغيل ("populate () ليس إعادة إدخال")) ، وأضف تعليقًا قبل هذا السطر ، ثم إضافة ، بنفس المسافة البادئة ، self.app_configs = {}. هذا يبدو هكذا:

            if self.loading:
                # منع مكالمات إعادة الدخول لتجنب تشغيل appconfig.ready ()
                # الأساليب مرتين.
# Raise RuntimeError ("Populate () ليس reentrant")
                self.app_configs = {}
            self.loading = True
يمكنك بعد ذلك التحقق من المشروع مرة أخرى وفضح الخطأ.

python manage.py check
ثم يمكنك رؤية الخطأ وإصلاحه. عندما يتم إصلاحه وتجمع الرمز بدون أخطاء ، تأكد من تغيير الملف مرة أخرى بحيث يبدو هذا:

            if self.loading:
                # منع مكالمات إعادة الدخول لتجنب تشغيل appconfig.ready ()
                # الأساليب مرتين.
                raise RuntimeError("populate() isn't reentrant")
# self.app_configs = {}
            self.loading = True
شريطة أن يكون الخادم متصلاً بالإنترنت ، عندما نقوم بإجراء أي تغييرات أخرى عليه ، نحتاج إلى استخدام الأمر التالي لإعادة تحميل الخادم:

sudo systemctl reload apache2
مذهل! ولكن ماذا عن إرسال البريد؟ للبدء في إرسال البريد الإلكتروني ، سنحتاج أولاً إلى تحديث تكوين المجال. يجب أن يكون هذا في لوحة DNS الخاصة بك في Squarespace ، أو أي مسجل اسم المجال الذي اخترته. سنحتاج أيضًا إلى تثبيت التكوين وإضافة ، وتشغيل بعض الأوامر. أولاً ، دعنا نحصل على عنوان IPv6 للخادم. سنفتح بعد ذلك DNS وإضافة السجلات. للحصول على عنوان IPv6 للخادم ، استخدم هذا الأمر:

ip -6 addr
الآن ، يمكننا إضافة السجلات التالية إلى إعدادات DNS. سجلاتي تبدو هكذا. ومع ذلك ، بالنسبة لسجلاتك ، يجب استبدال عنوان IP بـ IP الخاص بك (لا 75.147.182.214 ، هذا هو لي). أضف أيضًا مجالك بدلاً من femmebabe.com ، وكذلك عنوان IPv6 الخاص بك الموجود مع الأمر السابق (لا يمكنك استخدام Mine ، Fe80 :: 725a: FFF: FE49: 3E02). لا تقلق بشأن DomainKey في الوقت الحالي ، يتم إنشاء هذا عند إعداد Postfix ، خادم البريد ، مع OpendKim ، وطباعة المفتاح. سنقوم بتكوين هذا الأخير. @ أ ن/أ 75.147.182.214 @ MX 10 femmebabe.com @ PTR ن/أ femmebabe.com @ رسالة قصيرة ن/أ txt @ v = spf1 mx ip75.147.182.214ip6: fe80 :: 725a: fff: fe49: 3e02 ~ all default._bimi رسالة قصيرة ن/أ v = bimi1 ؛ l = https: //femmebabe.com/media/static/femmebabe.svg _dmarc رسالة قصيرة ن/أ V = DMARC1 ؛ P = لا شيء Sendonly._domainkey رسالة قصيرة ن/أالآن ، سنحتاج إلى إضافة بعض التكوين المستمر لـ Postfix. كل ما نحتاج إلى فعله هو التأكد من استبدال اسم المجال ، femmebabe.com ، باسم المجال الذي تستخدمه. دعونا نلقي نظرة على جميع ملفات التكوين واحدة تلو الأخرى ، وقم بتثبيتها في دليل يسمى config في مشروعنا ، للتثبيت على نظام التشغيل.

nano config/etc_postfix_main.cf
أضف هذا النص إلى الملف

# انظر /usr/share/postfix/main.cf.dist للحصول على نسخة أكثر اكتمالا


# Debian محدد: تحديد اسم الملف سيؤدي إلى الأول
# سطر من هذا الملف لاستخدامه كاسم.  التخلف عن السداد
# IS /etc /mailname.
# myorigine = /etc /mailname

smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
biff = no

# الإلحاح .domain هو وظيفة MUA.
append_dot_mydomain = no

# Uncomment هو السطر التالي لإنشاء تحذيرات "البريد المتأخر"
# تأخير _warning_time = 4h

readme_directory = no

# راجع http://www.postfix.org/compatibility_readme.html - الافتراضي إلى 3.6 ON
# تثبيتات جديدة.
compatibility_level = 3.6



# المعلمات TLS
smtpd_tls_cert_file=/etc/letsencrypt/live/femmebabe.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/femmebabe.com/privkey.pem
smtpd_tls_security_level=may

smtp_tls_CApath=/etc/ssl/certs
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

smtpd_relay_restrictions = permit_sasl_authenticated, defer_unauth_destination
myhostname = femmebabe.com
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
mydestination = femmebabe.com, localhost, $myhostname
smtp_helo_name = femmebabe.com
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = all

# تكوين milter
milter_default_action = accept
milter_protocol = 6
smtpd_milters = local:/opendkim/opendkim.sock
non_smtpd_milters = $smtpd_milters

smtp_tls_security_level = encrypt
smtp_tls_loglevel = 1

virtual_transport=lmtp:unix:private/dovecot-lmtp

smtpd_sasl_path = private/auth
التكوين التالي!

nano config/etc_postfix_master.cf
أضف هذه الخطوط:

# 
# ملف تكوين عملية Postfix Master.  للحصول على تفاصيل حول التنسيق
# من الملف ، انظر الصفحة اليدوية (5) (الأمر: "Man 5 Master" أو
# على الإنترنت: http://www.postfix.org/master.5.html).
# 
# لا تنس أن تنفذ "postfix Reload" بعد تحرير هذا الملف.
# 
# ================================================== =========================
# نوع الخدمة الخاصة غير المحمولة chroot wakeup maxproc command + args
# (نعم) (نعم) (لا) (أبدا) (100)
# ================================================== =========================
smtp      inet  n       -       y       -       -       smtpd
# smtp inet n - y - 1 postscreen
# SMTPD PASS - - Y - - SMTPD
# Dnsblog Unix - - y - 0 dnsblog
# Tlsproxy Unix - - y - 0 tlsproxy
# اختر واحدة: تمكين تقديم عملاء Loopback فقط ، أو لأي عميل.
# 127.0.0.1:Submission Inet N - Y - - SMTPD
submission inet n       -       y       -       -       smtpd
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_tls_wrappermode=no
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth
# -o syslog_name = postfix/التقديم
# -O SMTPD_TLS_SECURITY_LEVEL = ENCRYPT
# -o smtpd_sasl_auth_enable = نعم
# -O SMTPD_TLS_AUTH_ONLY = نعم
# -o smtpd_reject_unlisted_recipient = لا
# -o smtpd_client_restrictions = $ mua_client_restrictions
# -o smtpd_helo_restrictions = $ mua_helo_restrictions
# -o smtpd_sender_restrictions = $ mua_sender_restrictions
# -o smtpd_recipient_restrictions =
# -o SMTPD_RELAY_RESTRICTIONS = permot_sasl_authenticated ، رفض
# -o milter_macro_daemon_name = نشأ
# اختر واحدة: تمكين SMTPs لعملاء الاسترجاع فقط ، أو لأي عميل.
# 127.0.0.1:SMTPS inet n - y - - smtpd
# smtps inet n - y - - smtpd
# -o syslog_name = postfix/smtps
# -O SMTPD_TLS_WRAPPERMODE = نعم
# -o smtpd_sasl_auth_enable = نعم
# -o smtpd_reject_unlisted_recipient = لا
# -o smtpd_client_restrictions = $ mua_client_restrictions
# -o smtpd_helo_restrictions = $ mua_helo_restrictions
# -o smtpd_sender_restrictions = $ mua_sender_restrictions
# -o smtpd_recipient_trival =
# -o SMTPD_RELAY_RESTRICTIONS = permot_sasl_authenticated ، رفض
# -o milter_macro_daemon_name = نشأ
# 628 Inet N - Y - - QMQPD
pickup    unix  n       -       y       60      1       pickup
cleanup   unix  n       -       y       -       0       cleanup
qmgr      unix  n       -       n       300     1       qmgr
# QMGR UNIX N - N 300 1 OQMG
tlsmgr    unix  -       -       y       1000?   1       tlsmgr
rewrite   unix  -       -       y       -       -       trivial-rewrite
bounce    unix  -       -       y       -       0       bounce
defer     unix  -       -       y       -       0       bounce
trace     unix  -       -       y       -       0       bounce
verify    unix  -       -       y       -       1       verify
flush     unix  n       -       y       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       y       -       -       smtp
relay     unix  -       -       y       -       -       smtp
        -o syslog_name=postfix/$service_name
# -o smtp_helo_timeout = 5 -o smtp_connect_timeout = 5
showq     unix  n       -       y       -       -       showq
error     unix  -       -       y       -       -       error
retry     unix  -       -       y       -       -       error
discard   unix  -       -       y       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       y       -       -       lmtp
anvil     unix  -       -       y       -       1       anvil
scache    unix  -       -       y       -       1       scache
postlog   unix-dgram n  -       n       -       1       postlogd
# 
# ================================================== ==================
# واجهات لبرنامج غير postfix. تأكد من فحص الدليل
# صفحات برنامج غير Postfix لمعرفة الخيارات التي يريدها.
# 
# تستخدم العديد من الخدمات التالية تسليم Postfix Pipe (8)
# عامل.  انظر صفحة pipe (8) امرأة للحصول على معلومات حول $ {المستلم}
# وخيارات مغلف الرسائل الأخرى.
# ================================================== ==================
# 
# MailDrop. راجع ملف postfix maildrop_readme للحصول على التفاصيل.
# حدد أيضًا في main.cf: maildrop_destination_recipient_limit = 1
# 
maildrop  unix  -       n       n       -       -       pipe
  flags=DRXhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
# 
# ================================================== ==================
# 
# يمكن أن تستخدم إصدارات Cyrus الحديثة إدخال "LMTP" Master.CF الحالي.
# 
# حدد في cyrus.conf:
# lmtp cmd = "lmtpd -a" الاستماع = "LocalHost: LMTP" proto = tcp4
# 
# حدد في main.cf واحد أو أكثر مما يلي:
# mailbox_transport = lmtp: inet: localhost
# virtual_transport = lmtp: inet: localhost
# 
# ================================================== ==================
# 
# Cyrus 2.1.5 (Amos Gouaux)
# حدد أيضًا في main.cf: cyrus_destination_recipient_limit = 1
# 
# Cyrus Unix - n n - - الأنابيب
# flags = drx user = cyrus arg =/cyrus/bin/deliver
# 
# ================================================== ==================
# مثال قديم على التسليم عبر سايروس.
# 
# القديم -cyrus unix - n n - - الأنابيب
# flags = r user = cyrus argv =/cyrus/bin/deliver
# 
# ================================================== ==================
# 
# راجع ملف postfix UUCP_ReadMe للحصول على تفاصيل التكوين.
# 
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
# 
# طرق التسليم الخارجية الأخرى.
# 
ifmail    unix  -       n       n       -       -       pipe
  flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp     unix  -       n       n       -       -       pipe
  flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix -       n       n       -       2       pipe
  flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
mailman   unix  -       n       n       -       -       pipe
  flags=FRX user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py ${nexthop} ${user}
وتكوين OpendKim. يحدد OpendKim خوادم البريد الإلكتروني مع مفاتيح المجال لجعلها أكثر أمانًا. بدونه ، لم يتم توقيع البريد وقد لا يصل إلى صندوق الوارد.

nano config/etc_default_opendkim
أضف هذه الخطوط:

# ملاحظة: هذا ملف تكوين قديم. لا يستخدمه Opendkim
# خدمة النظام. يرجى استخدام معلمات التكوين المقابلة في
# /etc/opendkim.conf بدلاً من ذلك.
# 
# في السابق ، يمكن للمرء تحرير الإعدادات الافتراضية هنا ، ثم ينفذ
# /lib/opendkim/opendkim.service.generate لإنشاء ملفات تجاوز النظام إلى
# /etc/systemd/system/opendkim.service.d/override.conf و
# /etc/tmpfiles.d/opendkim.conf. على الرغم من أن هذا لا يزال ممكنًا ، إلا أنه الآن
# الموصى بها لضبط الإعدادات مباشرة في /etc/opendkim.conf.
# 
# daemon_opts = ""
# تغيير إلى/var/spool/postfix/run/opendkim لاستخدام مقبس UNIX مع
# postfix في chroot:
# Rundir =/var/spool/postfix/run/opendkim
RUNDIR=/run/opendkim
# 
# عدم التحديد لتحديد مقبس بديل
# لاحظ أن إعداد هذا سيتجاوز أي قيمة مقبس في opendkim.conf
# تقصير:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# استمع إلى جميع واجهات المنفذ 54321:
# المقبس = inet: 54321
# استمع إلى الاسترجاع على المنفذ 12345:
# Socket = inet: 12345@localhost
# الاستماع هو 192.0.2.1 هو المنفذ 12345:
# المقبس = inet: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=

nano config/etc_dovecot_conf.d_10-master.conf
أضف هذه الخطوط:

0-master.conf 
# default_process_limit = 100
# default_client_limit = 1000

# الحد الافتراضي VSZ (حجم الذاكرة الظاهرية) لعمليات الخدمة. هذا أساسا
# تهدف إلى القبض على العمليات التي تسرب الذاكرة وقتلها قبل أن يأكلوا
# كل شئ.
# default_vsz_limit = 256m

# يستخدم مستخدم تسجيل الدخول داخليًا بواسطة عمليات تسجيل الدخول. هذا هو الأكثر ثقة
# المستخدم في نظام Dovecot. لا ينبغي أن يكون لديه الوصول إلى أي شيء على الإطلاق.
# default_login_user = dovenull

# يتم استخدام المستخدم الداخلي من خلال العمليات غير المحببة. يجب أن تكون منفصلة عن
# مستخدم تسجيل الدخول ، بحيث لا يمكن أن تزعج عمليات تسجيل الدخول عمليات أخرى.
# default_internal_user = dovecot

service imap-login {
  inet_listener imap {
    # منفذ = 143
  }
  inet_listener imaps {
    # منفذ = 993
    # SSL = نعم
  }

  # عدد الاتصالات للتعامل معها قبل بدء عملية جديدة. عادة
  # القيم المفيدة الوحيدة هي 0 (غير محدود) أو 1. 1 أكثر أمانًا ، ولكن 0
  # أسرع. <doc/wiki/logInProcess.txt>
  # service_count = 1

  # عدد العمليات التي تستمر دائمًا في انتظار المزيد من الاتصالات.
  # process_min_avail = 0

  # إذا قمت بتعيين Service_Count = 0 ، فربما تحتاج إلى تنمية هذا.
  # vsz_limit = $ default_vsz_limit
}

service pop3-login {
  inet_listener pop3 {
    # منفذ = 110
  }
  inet_listener pop3s {
    # منفذ = 995
    # SSL = نعم
  }
}

service submission-login {
  inet_listener submission {
    # منفذ = 587
  }
}

service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    group = postfix
    mode = 0666
    user = postfix
  }

  # إنشاء مستمع inet فقط إذا لم تتمكن من استخدام مقبس UNIX أعلاه
  # inet_lister lmtp {
    # تجنب جعل LMTP مرئيًا للإنترنت بأكمله
    # العنوان =
    # منفذ =
  # }
}

service imap {
  # معظم الذاكرة تذهب إلى ملفات mmap () جي. قد تحتاج إلى زيادة هذا
  # الحد إذا كان لديك صناديق بريد ضخمة.
  # vsz_limit = $ default_vsz_limit

  # الأعلى. عدد عمليات IMAP (الاتصالات)
  # Process_Limit = 1024
}

service pop3 {
  # الأعلى. عدد عمليات pop3 (الاتصالات)
  # Process_Limit = 1024
}

service submission {
  # الأعلى. عدد عمليات تقديم SMTP (اتصالات)
  # Process_Limit = 1024
}

service auth {
  # يشير Auth_socket_path إلى مقبس userdb هذا افتراضيًا. عادة
  # تستخدمها Dovecot-LDA ، و doveadm ، وربما عملية IMAP ، وما إلى ذلك.
  # الأذونات الكاملة لهذا المقبس قادرة على الحصول على قائمة بجميع أسماء المستخدمين و
  # احصل على نتائج عمليات البحث عن USERDB للجميع.
  # 
  # يسمح وضع 0666 الافتراضي لأي شخص بالاتصال بالمقبس ، ولكن
  # لن تنجح عمليات البحث عن userdb إلا إذا قام userDB بإرجاع حقل "UID"
  # يطابق UID لعملية المتصل. أيضا إذا كان المتصل UID أو GID يطابق
  # مقبس UID أو gid ينجح البحث. أي شيء آخر يسبب الفشل.
  # 
  # لمنح المتصل أذونات كاملة للبحث عن جميع المستخدمين ، قم بتعيين الوضع على
  # شيء آخر غير 0666 و Dovecot يتيح لـ kernel تطبيق
  # أذونات (على سبيل المثال ، 0777 تسمح للجميع أذونات كاملة).
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}

service auth-worker {
  # يتم تشغيل عملية عامل المصادقة كجذر افتراضيًا ، بحيث يمكن الوصول إليها
  # /إلخ/الظل. إذا لم يكن ذلك ضروريًا ، فيجب تغيير المستخدم إلى
  # $ default_interal_user.
  # المستخدم = الجذر
}

service dict {
  # إذا تم استخدام وكيل DICT ، فيجب أن يكون لعمليات البريد إمكانية الوصول إلى المقبس.
  # على سبيل المثال: الوضع = 0660 ، المجموعة = vmail و global mail_access_groups = vmail
  unix_listener dict {
    # الوضع = 0600
    # المستخدم =
    # المجموعة =
  }
}
مرة أخرى ، تأكد من استبدال المجال في كل هذه الملفات ، Femmebabe.com ، بالمجال الذي حددته. قم بتحرير الملف التالي ، تكوين Dovecot ،

nano config/etc_dovecot_dovecot
وأضف هذه الخطوط

## ملف تكوين Ovecot

# إذا كنت في عجلة من أمرك ، راجع http://wiki2.dovecot.org/quickconfiguration

# يعطي الأمر "DoveConf -N" إخراجًا نظيفًا للإعدادات التي تم تغييرها. استخدمه
# بدلاً من نسخ الملفات ولصقها عند النشر إلى قائمة البريد Dovecot.

# '# 'الشخصية وكل شيء بعد معاملته كتعليقات. مساحات إضافية
# وتجاهل علامات التبويب. إذا كنت ترغب في استخدام أي من هذه بشكل صريح ، فضع
# value inside quotes, eg.: key = "# شار والمسافة البيضاء المتأخرة "

# يمكن تجاوز معظم الإعدادات (وليس كلها) بواسطة بروتوكولات مختلفة و/أو
# IPS المصدر/الوجهة عن طريق وضع الإعدادات داخل الأقسام ، على سبيل المثال:
# بروتوكول IMAP {} ، محلي 127.0.0.1 {} ، Remote 10.0.0.0/8 {}

# يتم عرض القيم الافتراضية لكل إعداد ، فليس من المطلوب عدمه
# أولئك. هذه استثناءات لهذا: لا توجد أقسام (مثل مساحة الاسم {})
# أو تتم إضافة إعدادات البرنامج المساعد افتراضيًا ، فهي مدرجة فقط كأمثلة.
# المسارات هي أيضًا أمثلة فقط مع الإعدادات الافتراضية الحقيقية التي تعتمد على التكوين
# خيارات. المسارات المدرجة هنا للتكوين -prefix =/usr
# --sysconfdir =/etc-localstatedir =/var

# تمكين البروتوكولات المثبتة
!include_try /usr/share/dovecot/protocols.d/*.protocol

# قائمة مفصولة مفصولة من IPs أو المضيفين حيث للاستماع للاتصالات.
# يستمع "*" في جميع واجهات IPv4 ، "::" يستمع في جميع واجهات IPv6.
# إذا كنت ترغب في تحديد المنافذ غير الافتراضية أو أي شيء أكثر تعقيدًا ،
# تحرير conf.d/master.conf.
# الاستماع = *، ::

# الدليل الأساسي حيث لتخزين بيانات وقت التشغيل.
# base_dir =/var/run/dovecot/

# اسم هذه الحالة. في الإعداد متعدد الثورات DoVeadm والأوامر الأخرى
# يمكن استخدام -i <alute_name> لتحديد المثيل المستخدم (بديل
# إلى -c <config_path>). تمت إضافة اسم المثيل أيضًا إلى عمليات Dovecot
# في الإخراج PS.
# easule_name = dovecot

# تحية رسالة للعملاء.
# login_greeting = dovecot جاهز.

# قائمة مفصولة الفضاء من نطاقات الشبكة الموثوق بها. اتصالات من هذه
# يُسمح لـ IPs بتجاوز عناوين IP ومنافذها (لتسجيلها و
# لفحص المصادقة). يتم تجاهل disable_plaintext_auth
# هذه الشبكات. عادةً ما تحدد خوادم الوكيل IMAP هنا.
# login_trusted_networks =

# قائمة مفصولة الفضاء من مآخذ الوصول إلى تسجيل الدخول (مثل TCPWRAP)
# login_access_sockets =

# مع proxy_maybe = نعم إذا كانت وجهة الوكيل تتطابق مع أي من هذه العنوانات الفكرية ، لا تفعل ذلك
# البرامج. هذا ليس ضروريًا بشكل طبيعي ، ولكن قد يكون مفيدًا إذا كانت الوجهة
# IP على سبيل المثال IP Balancer's IP.
# Auth_proxy_self =

# إظهار المزيد من عناوين عملية المطوّل (في PS). يظهر حاليا اسم المستخدم و
# عنوان IP. مفيد لرؤية من يستخدمون بالفعل عمليات IMAP
# (على سبيل المثال ، صناديق البريد المشتركة أو إذا تم استخدام نفس UID لحسابات متعددة).
# Verbose_proctitle = لا

# إذا تم قتل جميع العمليات عند إيقاف تشغيل عملية Dovecot Master.
# إن تعيين هذا إلى "لا" يعني أنه يمكن ترقية DoveCot بدون
# إجبار اتصالات العميل الحالية على الإغلاق (على الرغم من أن ذلك قد يكون أيضًا
# مشكلة إذا كانت الترقية على سبيل المثال بسبب إصلاح الأمن).
# stowddown_clients = نعم

# إذا غير صفري ، قم بتشغيل أوامر البريد عبر هذه الاتصالات العديدة إلى خادم DoVeadm ،
# بدلاً من تشغيلها مباشرة في نفس العملية.
# doveadm_worker_count = 0
# مقبس UNIX أو المضيف: منفذ يستخدم للاتصال بخادم DoVeadm
# doveadm_socket_path = doveadm-server

# قائمة مفصول المساحة من متغيرات البيئة التي يتم الحفاظ عليها على Dovecot
# بدء التشغيل وانتقل إلى جميع عمليات أطفالها. يمكنك أيضا إعطاء
# مفتاح = أزواج القيمة لوضع إعدادات محددة دائمًا.
# import_environment = tz

## 
## إعدادات خادم القاموس
## 

# يمكن استخدام القاموس لتخزين المفتاح = قوائم القيمة. يستخدم هذا من قبل عدة
# الإضافات. يمكن الوصول إلى القاموس إما مباشرة أو على الرغم من أ
# خادم القاموس. أسماء القاموس التالية لأوريا أسماء قيام القاموس بلوك بلوك إلى URIS
# عند استخدام الخادم. يمكن بعد ذلك الرجوع إليها باستخدام URIS بالتنسيق
# "Proxy :: <name>".

dict {
  # الحصص = mysql: /andc/dovecot/dovecot-dic-sql.conf.ext
}

# يتم تضمين معظم التكوين الفعلي أدناه. أسماء الملفات
# تم فرزها أولاً من خلال قيمة ASCII وتوحلها بهذا الترتيب. 00-prefixes
# في أسماء الملفات تهدف إلى تسهيل فهم الطلب.
!include conf.d/*.conf

# يمكن أيضًا أن يتم تضمين ملف التكوين دون إعطاء خطأ إذا
# لم يتم العثور عليها:
!include_try local.conf

passdb {
  driver = passwd-file
  args = /etc/dovecot/passwd
}
userdb {
  driver = passwd
}

protocols = imap pop3

# يسمح DoveCot بالاستماع إلى جميع اتصالات الإدخال (IPv4 / IPv6)

listen = *, ::
أضف كلمة مرور لمستخدم Dovecot:

nano config/etc_dovecot_passwd
الجزء الأول من الملف ، قبل القولون ، هو اسم المستخدم. يدل الجزء الأخير ، "YoursPassword" ، على كلمة المرور التي ترغب في إعطاء خادم البريد الخاص بك.

team:{plain}yourpassword
بعد ذلك ، تكوين Opendkim

nano config/etc_opendkim.conf
وأضف هذه الخطوط:

# هذا هو التكوين الأساسي للتوقيع والتحقق. يمكن أن يكون بسهولة
# تم تكييفها لتناسب تثبيت أساسي. انظر Opendkim.conf (5) و
# /usr/share/doc/opendkim/examples/opendkim.conf.sample for كاملة
# توثيق معلمات التكوين المتاحة.

Syslog			yes
SyslogSuccess		yes
# logwhy لا

# معلمات التوقيع والتحقق الشائعة. في دبيان ، رأس "من" هو
# مبالغ فيه ، لأنه غالبًا ما يكون مفتاح الهوية المستخدمة في أنظمة السمعة
# وبالتالي حساس الأمن إلى حد ما.
Canonicalization	relaxed/simple
Mode			s
SubDomains		no
OversignHeaders		From

# مجال التوقيع ، المحدد ، والمفتاح (مطلوب). على سبيل المثال ، قم بتنفيذ التوقيع
# للحصول على المجال "example.com" مع Selector "2020" (2020._domainkey.example.com) ،
# باستخدام المفتاح الخاص المخزن في /etc/dkimkeys/example.private. أكثر حبيبتي
# يمكن العثور على خيارات الإعداد في /usr/share/doc/opendkim/readme.opendkim.
# domain example.com
# محدد 2020
# keyfile /etc/dkimkeys/example.private

# في Debian ، يعمل Opendkim كمستخدم "OpendKim". مطلوب umask من 007 عندما
# باستخدام مقبس محلي مع MTAs التي تصل إلى المقبس باعتبارها غير محددة
# المستخدم (على سبيل المثال ، postfix). قد تحتاج إلى إضافة مستخدم "postfix" إلى المجموعة
# "Opendkim" في هذه الحالة.
UserID			opendkim
UMask			007

# مقبس لاتصال MTA (مطلوب). إذا كانت MTA داخل سجن chroot ،
# يجب التأكد من أن المقبس يمكن الوصول إليه. في دبيان ، يركض postfix في
# chroot in/var/spool/postfix ، وبالتالي يجب أن يكون مقبس UNIX
# تم تكوينها كما هو موضح في السطر الأخير أدناه.
# Socket Local: /run/opendkim/opendkim.sock
# مقبس inet: 8891@localhost
# مقبس inet: 8891
Socket			local:/var/spool/postfix/opendkim/opendkim.sock

PidFile			/run/opendkim/opendkim.pid

# المضيفين لتوقيعه بدلاً من التحقق ، الافتراضي هو 127.0.0.1. انظر
# قسم التشغيل في Opendkim (8) لمزيد من المعلومات.
# Internalhosts 192.168.0.0/16 ، 10.0.0.0/8 ، 172.16.0.0/12

# مرساة الثقة تتيح DNSSEC. في دبيان ، يتم توفير ملف مرساة الثقة
# بواسطة الحزمة DNS-ROOT-DATA.
TrustAnchorFile		/usr/share/dns/root.key
# خوادم الأسماء 127.0.0.1

# نطاقات الخريطة من العناوين إلى المفاتيح المستخدمة لتوقيع الرسائل
KeyTable           refile:/etc/opendkim/key.table
SigningTable       refile:/etc/opendkim/signing.table

# مجموعة من المضيفين الداخليين الذين يجب توقيع بريدهم
InternalHosts       /etc/opendkim/trusted.hosts

nano config/etc_default_opendkim
وأضف هذه الخطوط

# ملاحظة: هذا ملف تكوين قديم. لا يستخدمه Opendkim
# خدمة النظام. يرجى استخدام معلمات التكوين المقابلة في
# /etc/opendkim.conf بدلاً من ذلك.
# 
# في السابق ، يمكن للمرء تحرير الإعدادات الافتراضية هنا ، ثم ينفذ
# /lib/opendkim/opendkim.service.generate لإنشاء ملفات تجاوز النظام إلى
# /etc/systemd/system/opendkim.service.d/override.conf و
# /etc/tmpfiles.d/opendkim.conf. على الرغم من أن هذا لا يزال ممكنًا ، إلا أنه الآن
# الموصى بها لضبط الإعدادات مباشرة في /etc/opendkim.conf.
# 
# daemon_opts = ""
# تغيير إلى/var/spool/postfix/run/opendkim لاستخدام مقبس UNIX مع
# postfix في chroot:
# rundir =/wad/spool/postfix/run/opendkim
RUNDIR=/run/opendkim
# 
# عدم التحديد لتحديد مقبس بديل
# لاحظ أن إعداد هذا سيتجاوز أي قيمة مقبس في opendkim.conf
# تقصير:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# استمع إلى جميع واجهات المنفذ 54321:
# المقبس = inet: 54321
# استمع إلى الاسترجاع على المنفذ 12345:
# Socket = inet: 12345@localhost
# الاستماع هو 192.0.2.1 هو المنفذ 12345:
# المقبس = inet: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=
عندما نكون مستعدين لإعداد خادم PostFix الخاص بنا ، سنقوم بتشغيل الرمز أدناه ، مع تضمين اسم المجال المناسب. ابدأ بإنشاء نص

touch scripts/postfixsetup
sudo chmod a+x scripts/postfixsetup
nano scripts/postfixsetup
الآن ، في نانو ، تحرير محرر النصوص ، حتى يتضمن اسم المجال الخاص بك بدلاً من femmebabe.com.

# !
# إعداد postfix
cd $DIR
echo "Mail services configuration"
sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.backup
sudo cp config/etc_postfix_main.cf /etc/postfix/main.cf
sudo cp config/etc_postfix_master.cf /etc/postfix/master.cf
sudo cp config/etc_default_opendkim /etc/default/opendkim
sudo cp config/etc_dovecot_conf.d_10-auth.conf /etc/dovecot/conf.d/10-auth.conf
sudo cp config/etc_dovecot_conf.d_10-master.conf /etc/dovecot/conf.d/10-master.conf
sudo cp config/etc_dovecot_dovecot.conf /etc/dovecot/dovecot.conf
sudo cp config/etc_dovecot_passwd /etc/dovecot/passwd
sudo cp config/etc_opendkim.conf /etc/opendkim.conf
sudo cp config/etc_default_opendkim /etc/default/opendkim
sudo adduser postfix opendkim
sudo mkdir /etc/opendkim
sudo mkdir /etc/opendkim/keys
sudo mkdir /etc/opendkim/keys/femmebabe.com
sudo mkdir /var/spool/postfix/opendkim
sudo echo "*@femmebabe.com     sendonly._domainkey.femmebabe.com" | sudo tee -a /etc/opendkim/signing.table
sudo echo "sendonly._domainkey.femmebabe.com    femmebabe.com:sendonly:/etc/opendkim/keys/femmebabe.com/sendonly.private" | sudo tee -a /etc/opendkim/key.table
sudo echo "127.0.0.1" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "localhost" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "*.femmebabe.com" | sudo tee -a /etc/opendkim/trusted.hosts
sudo chown -R opendkim:opendkim /etc/opendkim
sudo opendkim-genkey -b 2048 -d femmebabe.com -D /etc/opendkim/keys/femmebabe.com -s sendonly -v
sudo chmod go-rw /etc/opendkim/keys
sudo chown opendkim:opendkim /etc/opendkim/keys/femmebabe.com/sendonly.private
sudo chown opendkim:postfix /var/spool/postfix/opendkim
cd $DIR
sudo cp mailbox/* /var/mail/
sudo chown :users /var/mail/*
sudo chmod -R a+rwx /var/mail/*
sudo systemctl restart opendkim postfix dovecot
sudo cat /etc/opendkim/keys/femmebabe.com/sendonly.txt | tr -d '\n' | sed 's/\s//g' | sed 's/""//g' | awk -F'[)(]' '{print $2}'
الآن ، قم بتشغيل البرنامج النصي المكتمل لتكوين Postfix و OpendKim و Dovecot.

./scripts/postfixsetup
بمجرد تشغيل هذا البرنامج النصي ، انسخ السطر الأخير الذي يطبعه ولصقه في تكوين DNS الخاص بك كقيمة لـ Sendonly._domainkey. هذا هو مفتاح OpendKim المستخدم لتحديد مجالك عند إرسال بريد آمن. مذهل! في غضون أيام قليلة ، يجب أن تكون قادرًا على إرسال بريد من الخادم شريطة تكوين كل شيء بشكل صحيح. إذا قمت للتو بتكوين DNS لخادم البريد الخاص بك ، فيجب أن يستغرق تحديث السجلات أقل من 72 ساعة. عادة ما يكون أسرع بكثير. يمكنك التحقق مما إذا كان الخادم الخاص بك يعمل باستخدام هذا الأمر ، وقدم بريدك الإلكتروني:

echo “test” | mail -s “Test Email” youremail@gmail.com
إذا كان كل شيء يعمل بشكل صحيح ، فيجب أن تكون قادرًا على إرسال بريد إلكتروني مع الخادم الخاص بك. إذا لم ينجح الأمر ، فحاول النظر إلى السجلات لمعرفة ما قد يكون الخطأ.

tail –lines 150 /var/log/mail.log
سيقدم هذا معلومات مطوّلة حول البريد الذي يتم إرساله بواسطة الخادم وما إذا كان يعمل بشكل صحيح. يجب أن تكون قادرًا على رؤية البريد الإلكتروني في صندوق الوارد الخاص بك أيضًا ، إذا لم يكن هناك ، تحقق من مجلد البريد العشوائي الخاص بك. ستحتاج أيضًا إلى تكوين الإعدادات الخاصة بك في الإعدادات الخاصة بك. اطلب من خادم البريد الإلكتروني الخاص بك التحدث إلى تطبيق Django الخاص بك ، المشروع. إضافة أو استبدال هذه الخطوط في الإعدادات الخاصة بك

EMAIL_HOST = DOMAIN
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_ADDRESS = 'team@femmebabe.com'
EMAIL_HOST_USER = 'team' # "love@mamasheen.com"
EMAIL_HOST_PASSWORD = config['EMAIL_HOST_PASSWORD']
DEFAULT_FROM_EMAIL = '{} <{}>'.format(SITE_NAME, EMAIL_HOST_USER)
لاحظ أننا نستخدم ملف التكوين للحصول على كلمة المرور. دعنا نقوم بتحميل هذا الملف في الإعدادات مثل ذلك ، في بداية الملف:

import os
import json

# فتح وتحميل التكوين
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
دعنا نقوم بإنشاء هذا الملف وإضافة مفتاح سري إليه ، وكذلك كلمة مرور البريد. لإنشاء مفتاح سري ، استخدم هذا الأمر ، مع أي طول تريده في النهاية:

openssl rand -base64 64
الآن ، انسخ النص الذي يفتح أنشئه وتعديله /etc/config.json

sudo nano /etc/config.json
أضف الأسطر التالية إلى ملفك ، مع المفتاح الذي يتم إنشاءه كمفتاح سري.

{
	"SECRET_KEY": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX-generated-using-openssl)",
	"EMAIL_HOST_PASSWORD": "yourpassword"
}
تنسيق JSON بسيط وسهل الاستخدام ، يمكننا أن نعلن عن مفاتيح أخرى نريد استخدامها في مشروعنا بهذه الطريقة أيضًا ، والحفاظ عليها منفصلة عن دليل مشروعنا حتى لا يتمكن المستخدمون الآخرون من الكتابة إليهم وبالتالي لا يمكن قراءته من دليل مشروعنا وحده. هذا الممارسة الموصى بها لمفاتيح API ، والتي سنستخدمها أكثر من عدد قليل هنا. ستحتاج أيضًا إلى عمل نسخة احتياطية من مشروعك للتأكد من حفظ كل شيء وستتمكن من استعادة عملك لاحقًا حتى لو لم تعد ترغب في استئجار خادم.

sudo backup
الآن ، حاول إرسال بريد إلكتروني HTML من خادم الويب ، شريطة إرسال واحدة من سطر الأوامر. استعد على مثيل المستخدم الخاص بك في shell ، وأرسل بريدًا إلكترونيًا HTML إلى هذا المستخدم من خلال Django. تغيير اسمي في الكود ، شارلوت ، إلى اسم المستخدم الخاص بك.

python manage.py shell
from django.contrib.auth.models import User
u = User.objects.get(username='Charlotte')
from users.email import send_welcome_email
send_welcome_email(u)
exit()
إذا لم ينجح الأمر الأول ، فتأكد من استخدامه

source venv/bin/activate
شريطة أن يتم إعداد كل شيء بشكل صحيح ، ستحصل الآن على بريد إلكتروني ترحيب في صندوق البريد الذي تم إرساله بواسطة تطبيق الويب الخاص بك. أحسنت! لقد قطعت شوطا طويلا. أردت أن أضيف ، إذا كنت تعاني من أي أخطاء على الإطلاق أثناء العمل في مشروع مثل هذا ، فلا تتردد في البحث عن إجابات وطلب المساعدة. Google ، من بين محركات البحث الأخرى ، هي موارد رائعة للبحث عن مساعدة البرمجة. ما عليك سوى البحث عن الخطأ الذي تحصل عليه ، وستتمكن من رؤية كيفية حل المشكلة الأخرى. أيضًا ، مرحبًا بك في الاتصال بي ، والمعلمين (المعلمين ، الأساتذة ، المعلمون) ، أي أقرانهم على الإنترنت متاحون للحصول على مساعدة البرمجة ، أو استشارة هذا الكتاب مرة أخرى أو موارد أخرى لإيجاد حلول للمشكلات التي تواجهها. أتفهم أن هذا ليس بالأمر السهل ، ولكن حتى لو كنت قد قرأت في هذا الحد ولم تكتب أي رمز ، فأنت تتعلم الكثير عن إنشاء تطبيق ويب من نقطة الصفر. تبرز نفسك على ظهره ، فأنت تقوم بعمل رائعوظيفة. شكرًا لك على قضاء الوقت لقراءة دليل تطوير الويب للطبعة الثالثة. في الإصدارات المستقبلية ، سأقوم بتضمين المزيد من الأمثلة المهمة التي تمت مناقشتها في بداية الوثيقة وسنقوم بعمق أكبر في عالم تطوير البرمجيات والأجهزة. ترقبوا ما سيأتي ، وأتطلع إلى تعليمك كيفية بناء برامج لا تصدق. نراكم في التالي






يغلق
صفحة 1
القفز
انظر المقال الكامل
مواصلة القراءة

يشتري | شراء مع التشفير



https://glamgirlx.com/ar/practical-web-based-deep -


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

اترك لي نصيحة في البيتكوين باستخدام هذا العنوان: 3KhDWoSve2N627RiW8grj6XrsoPT7d6qyE

© Glam Girl X 2025

شروط الخدمة