Praktikal na Web Based Deep Learning at Security sa pamamagitan ng Halimbawa

Daisylarawan ng profile

Sa pamamagitan ng Daisy

Praktikal na batay sa web na pag -aaral at seguridad sa pamamagitan ng halimbawa Pangatlong edisyon Charlotte Harper Hulyo 3, 2024 Foreword: Ang mga pagsasaalang -alang sa seguridad sa pagbuo ng software para sa web ay isang mahalagang bahagi ng anumang plano at pagpapatupad ng web developer habang ang engineering isang prototype na maaasahan, matatag, at kapaki -pakinabang para sa mga praktikal na layunin. Ang DOM (dokumento object markup), na may pagpapatupad ng HTML, JavaScript, at CSS pati na rin ang backend software na nagpapatupad ng Python, C/C ++, Java at Bash, bigyan ang mga web developer ng kalayaan at kapangyarihan upang lumikha ng isang iba't ibang mga proyekto na nagpapahayag pagkamalikhain, magbigay ng kadalian ng paggamit at pag -andar, naglalarawan ng pagpapakumbaba at karakter, at nagbibigay ng kadalian ng paggamit pati na rin ang kaginhawaan at mahahalagang serbisyo na lahat ay kaakit -akit sa average na joe, ang end user Naghahanap upang pumatay ng oras o makakuha ng isang bagay na tapos sa internet, karaniwang sa isang touchscreen smartphone aparato. Karamihan sa mga tao ay hindi alam kung saan magsisimula kung nais nilang bumuo ng isang website mula sa simula,malamang na magsimula sila sa website ng ibang tao at bumuo ng isang bagay na limitado sa pag -andar, pagiging maaasahan, kadalian ng paggamit at lalo na ang pagkamalikhain kapag maaari silang magkaroon ng lahat ng pinakabagong makapangyarihang mga tool sa kanilang pagtatapon upang makabuo ng isang bagay na kapaki -pakinabang nang walang pag -aaksaya ng oras ng pagpindot sa mga pindutan, at Lalo na ang pag -aaksaya ng pera na nagbabayad para sa mga mamahaling subscription sa software ng ilang mga tao na nais gamitin pa rin ibinigay na mga limitasyon sa kadalian ng paggamit at kakayahang umangkop. Kung mayroon kang ilang minuto upang mabasa ang librong ito at alamin kung ano ang nais kong ituro sa iyo, o kahit na makipag -usap sa akin nang personal tungkol sa iyong mga layunin at makakuha ng ilang gabay sa tamang direksyon, at hinikayat na malaman na mag -code at magsulat ng iyong sariling software . Tungkol sa akin: Ako ay isang developer ng software na may malawakAnge ng karanasan sa C/C ++, Java, Python, HTML, CSS at JavaScript. Nagtatayo ako ng mga website na nais gamitin ng mga tao, nais na bisitahin, at kahit na gumon sa paggamit lamang upang malaman, muling likhain at patayin ang oras, at pinaka -mahalaga, nagbebenta ako ng software. Kung mayroon kang isang ideya tungkol sa eksaktong kung paano mo nais ang isang website upang tumingin at gumana, handa kang suportahan ako upang matugunan ko ang aking sariling mga pangangailangan habang nakatagpo ako sa iyo, at handa kang masakop ang mga gastos sa pagpapatakbo ng isang website sa iyong sarili, Itatayo ko sa iyo ang susunod na YouTube, Tiktok, Twitter, Google, o kahit na isang high-tech na security app lamang na maaari mong ma-access. Sa halip na subukang ibenta sa iyo ang aking oras, sinusubukan kong bilhin ang iyong: Nais kong pag -usapan ka sa pagbuo ng isang app (website) sa iyong sarili na may impormasyon na mayroon na, at turuan ka kung ano ang kailangan mong maging isang independiyenteng developer ng software, negosyante, nangunguna sa isang matagumpay na karera sa anumang larangan na nais mo. At hayaan akong maging malinaw, ang edukasyon na ibinibigay ko sa iyo ay hindi impormal. Maaari kang pumasok sa paaralan at malaman ang lahat ng ito sa aRMAL EDUKASYON, o basahin ang librong ito sa paaralan, kumpletuhin ang iyong mga takdang -aralin, at mag -alis ng isang mahusay na pakikitungo mula sa iyong edukasyon, ngunit hindi kita pormal na ilalagay sa mainit na upuan at hilingin sa iyo na makumpleto ang mga takdang -aralin. Hindi ako ang iyong propesor, maaari mong isipin ako tulad ng isang kaibigan na nais na gabayan ka patungo sa isang karera na hinimok ng iyong sariling personal na tagumpay. At hindi rin ako nagbebenta sa iyo ng tagumpay, kakailanganin mong bilhin ito sa iyong oras. Ang pag -aaral sa code ay may isang matarik na curve sa pag -aaral at hindi madali, o kahit na dapat. Kailangan mong magtrabaho nang husto hangga't maaari mong at magpatuloy na subukan at mabigo at subukang muli kahit na nabigo ka upang malaman at bumuo ng mga app sa iyong sarili. Iyon ay sa likas na katangian ng code mismo. Ang Code ay pinapatakbo ng isang tagatala na idinisenyo upang bigyan ang mga mensahe ng error sa programmer, at tuturuan ka nito kung paano mag -code, kahit na kinokopya mo lamang ang error sa iyong search engine at pagbabasa ng mga halimbawa ng ibang tao. At dapat kong sabihin, hindi mo kailangang maging sobrang mayaman, matalino, matagumpay,en Detalye na nakatuon o nakaayos upang makabuo ng isang app. Inaalagaan ng computer ang samahang iyon para sa iyo. Kailangan mo lamang magtiyaga sa pamamagitan ng pagsubok at pagkakamali, mapanatili ang pokus at magsikap sa iyong ginagawa, at magkakaroon ka ng isang matagumpay na karera sa kabuuan ng iyong ginagawa. Sino ako: Napagtanto ko na ang huling seksyon ay higit pa tungkol sa pag -aaral at ang iyong mga paraan mula sa aklat na ito. Sino ako eksakto? Iyon ay isang kumplikadong tanong. Hindi ako malinaw sa aking sarili, habang nagdurusa ako sa mga kondisyong medikal na maaaring maging mahirap para sa akin kahit na code o isulat ang aklat na ito minsan, habang ipinapakita ang mga hamon na may mga isyu sa pagsasapanlipunan at pagkakakilanlan na nagpapahirap sa aking buhay pagdating sa pagpapakilala sa aking sarili . Sa madaling sabi, kung binabasa mo ang librong ito, dinala mo ito sa bahay dahil na -flip mo ito at naisip na kapaki -pakinabang ito, o kahit na nabasa mo lang ito, sa iyo ako ay isang katulad na indibidwal na nais na makita kang magtagumpay sa lahat ng ginagawa mo. Ako ay isang inhinyero sa aking sarili, isang softwarenag -develop, at isang mag -aaral, at isinusulat ko ang librong ito para sa iba pang mga mag -aaral na nais na gawing mas madali ang kanilang buhay sa pamamagitan ng pagkakaroon ng isang handbook ng software na kailangan nilang gawing mas madali ang kanilang buhay sa pamamagitan ng pagbibigay ng mga halimbawa upang kopyahin na magkakasama tulad ng isang malaking palaisipan sa isang nagtatrabaho , kapaki -pakinabang, malaki, pag -andar, cohesive, at nakakaengganyo na app na maaaring magmaneho ng tagumpay kahit na ang linya ng negosyo. Lalo na, ito ang ginagawa ko: Nagtatayo ako ng mga app upang matulungan ang aking sarili at ang ibang tao ay magtagumpay. Ako rin ay isang may -akda, kahit na ito ang aking unang publikasyon na balak kong makumpleto upang magkasama ang aking portfolio sa isang kapaki -pakinabang na dokumento, at ako ay isang artista din. Aaminin ko ito sa iyo, ako ay uri ng isang kakaibang tao. Hindi ako perpekto, pinatakbo ko ang INS kasama ang batas kahit na humahantong sa akin na mag -iwan ng mga kolehiyo at unibersidad at mag -iwan ng mga estado upang subukang gumawa ng isang pangalan para sa aking sarili na may higit na tagumpay. Ako ay isang babae sa pamamagitan ng kapanganakan, nagsusuot ako ng pampaganda, kumuha ng litrato ng aking sarili, magsuot ng damit at iba pang damit ng mga kababaihan, at nananatili akong may kamalayan sa aking sarili bilang isanglalaki sa pamamagitan ng kalikasan. Nagkaroon ako ng mga isyu sa ibang mga tao sa nakaraan na humantong sa mga pakikibaka sa pagsulat at pagbuo ng mga webapp, at humihingi ako ng paumanhin na hindi ko pa nakuha ang aklat na ito sa iyong mga kamay nang mas maaga: kailangan mo ito. Gusto mong basahin at isulat ang code na katulad ng minahan at gumagana tulad ng minahan at ginagawa ang parehong bagay ngunit mas mahusay, dahil kung makakaya mong bilhin ang librong ito sa halip na mashing ang iyong keyboard tulad ng ginagawa ko upang lumikha lamang ng isang libro sa iyong sarili na humihiling ng pera Para dito, mayroon kang mga mapagkukunan na kailangan mong maging matagumpay sa iyong buhay. Nagkaroon ako ng lahat ng uri ng mga isyu sa paglaki ng pamilya, mga kondisyon ng kalusugan, mga doktor, media, at batas, at ang aking code ay malalim na sumasalamin sa pakikibaka na pagkababae at babaeng kalikasan sa isang nahahati at bigo na mundo. Gayunpaman, ang librong ito ay isang bagay na labis kong pinapahalagahan, ang aking sanggol, ang aking portfolio, at ang aking kabuhayan, kaya pinahahalagahan ko ang iyong pagsasaalang -alang kapag kinuha mo ang teksto sa bahay at maingat na sinimulan ito upang malaman mula sa akin. Mangyaring tandaan na hindi ako perpekto,Ang libro ay magkakaroon ng mga pagkakamali, pagbabago, at mga bagong edisyon, at kakailanganin mong mag -isip sa iyong lohikal na utak hangga't makakaya upang magkaroon ng isang matagumpay na karanasan sa aking pagsulat. Gayundin, maunawaan na ang ibig kong sabihin ay mabuti para sa iyo kahit na nahaharap ka sa mga hamon kapag nagsusulat. Isipin ito tulad nito: Kapag maaari ka lamang magrenta ng isang computer system upang gawin ang anumang maaari mong isipin sa digital na puwang, itabi ang lahat ng impormasyong nakatagpo mo, #$%! Yze at ayusin ito, at maunawaan mo ito, gagawin mo Hindi maiiwasang makatagpo ng mga paghihirap sa impormasyong iyong ingesting at kahit na pag -publish. Sinasabi ko ito sa iyo dahil nakatagpo ako ng parehong mga paghihirap. Gamitin ang librong ito sa iyong sariling peligro, makipagtulungan sa iyong komunidad at mga komunidad na magagamit mo upang makabuo ng software sa loob ng isang ligtas na setting, at huwag kumuha ng mga bagay nang personal kapag nabigo ka o kahit na magtagumpay sa maling paraan: ganyan ang nakuha ko sa ngayon , at kung bakit maaari kong dalhin sa iyo ang tekstong ito at tulungan kang magtagumpay nang walang pag -iiba sa isang landas ng kabaliwan na dahonAko ay wasak, napunit at nag -fray habang nakatagpo ako ng mga ordinaryong problema na ginagawa ng lahat sa isang pandaigdigang sukat salamat sa paralellistic global scale ng network kung saan tayo gagana, ang internet. Maaaring hindi ka masyadong pamilyar sa kung sino ako ...
Praktikal na Web Based Deep Learning at Security sa pamamagitan ng Halimbawa

Praktikal na batay sa web na pag -aaral at seguridad sa pamamagitan ng halimbawa Pangatlong edisyon Charlotte Harper Hulyo 3, 2024 Foreword: Ang mga pagsasaalang -alang sa seguridad sa pagbuo ng software para sa web ay isang mahalagang bahagi ng anumang plano at pagpapatupad ng web developer habang ang engineering isang prototype na maaasahan, matatag, at kapaki -pakinabang para sa mga praktikal na layunin. Ang DOM (dokumento object markup), na may pagpapatupad ng HTML, JavaScript, at CSS pati na rin ang backend software na nagpapatupad ng Python, C/C ++, Java at Bash, bigyan ang mga web developer ng kalayaan at kapangyarihan upang lumikha ng isang iba't ibang mga proyekto na nagpapahayag pagkamalikhain, magbigay ng kadalian ng paggamit at pag -andar, naglalarawan ng pagpapakumbaba at karakter, at nagbibigay ng kadalian ng paggamit pati na rin ang kaginhawaan at mahahalagang serbisyo na lahat ay kaakit -akit sa average na joe, ang end user Naghahanap upang pumatay ng oras o makakuha ng isang bagay na tapos sa internet, karaniwang sa isang touchscreen smartphone aparato. Karamihan sa mga tao ay hindi alam kung saan magsisimula kung nais nilang bumuo ng isang website mula sakumamot, malamang na magsimula sila sa website ng ibang tao at bumuo ng isang bagay na limitado sa pag -andar, pagiging maaasahan, kadalian ng paggamit at lalo na ang pagkamalikhain kapag maaari silang magkaroon ng lahat ng pinakabagong mga makapangyarihang tool sa kanilang pagtatapon upang makabuo ng isang bagay na kapaki -pakinabang nang walang pag -aaksaya ng mga pindutan ng pagpindot sa oras . Kung mayroon kang ilang minuto upang mabasa ang librong ito at alamin kung ano ang nais kong ituro sa iyo, o kahit na makipag -usap sa akin nang personal tungkol sa iyong mga layunin at makakuha ng ilang gabay sa tamang direksyon, at hinikayat na malaman na mag -code at magsulat ng iyong sariling software . Tungkol sa akin: Ako ay isang developer ng softwareSaklaw ng karanasan sa C/C ++, Java, Python, HTML, CSS at JavaScript. Nagtatayo ako ng mga website na nais gamitin ng mga tao, nais na bisitahin, at kahit na gumon sa paggamit lamang upang malaman, muling likhain at patayin ang oras, at pinaka -mahalaga, nagbebenta ako ng software. Kung mayroon kang isang ideya tungkol sa eksaktong kung paano mo nais ang isang website upang tumingin at gumana, handa kang suportahan ako upang matugunan ko ang aking sariling mga pangangailangan habang nakatagpo ako sa iyo, at handa kang masakop ang mga gastos sa pagpapatakbo ng isang website sa iyong sarili, Itatayo ko sa iyo ang susunod na YouTube, Tiktok, Twitter, Google, o kahit na isang high-tech na security app lamang na maaari mong ma-access. Sa halip na subukang ibenta sa iyo ang aking oras, sinusubukan kong bilhin ang iyong: Nais kong pag -usapan ka sa pagbuo ng isang app (website) sa iyong sarili na may impormasyon na mayroon na, at turuan ka kung ano ang kailangan mong maging isang independiyenteng developer ng software, negosyante, nangunguna sa isang matagumpay na karera sa anumang larangan na nais mo. At hayaan akong maging malinaw, ang edukasyon na ibinibigay ko sa iyo ay hindi impormal. Maaari kang pumasok sa paaralan at malaman ang lahat ng ito sa aPormal na edukasyon, o basahin ang librong ito sa paaralan, kumpletuhin ang iyong mga takdang -aralin, at mag -alis ng isang mahusay na pakikitungo mula sa iyong edukasyon, ngunit hindi kita pormal na ilalagay sa mainit na upuan at hilingin sa iyo na makumpleto ang mga takdang -aralin. Hindi ako ang iyong propesor, maaari mong isipin ako tulad ng isang kaibigan na nais na gabayan ka patungo sa isang karera na hinimok ng iyong sariling personal na tagumpay. At hindi rin ako nagbebenta sa iyo ng tagumpay, kakailanganin mong bilhin ito sa iyong oras. Ang pag -aaral sa code ay may isang matarik na curve sa pag -aaral at hindi madali, o kahit na dapat. Kailangan mong magtrabaho nang husto hangga't maaari mong at magpatuloy na subukan at mabigo at subukang muli kahit na nabigo ka upang malaman at bumuo ng mga app sa iyong sarili. Iyon ay sa likas na katangian ng code mismo. Ang Code ay pinapatakbo ng isang tagatala na idinisenyo upang bigyan ang mga mensahe ng error sa programmer, at tuturuan ka nito kung paano mag -code, kahit na kinokopya mo lamang ang error sa iyong search engine at pagbabasa ng mga halimbawa ng ibang tao. At dapat kong sabihin, hindi mo kailangang maging sobrang mayaman, matalino,essful, o kahit na detalye na nakatuon o nakaayos upang makabuo ng isang app. Inaalagaan ng computer ang samahang iyon para sa iyo. Kailangan mo lamang magtiyaga sa pamamagitan ng pagsubok at pagkakamali, mapanatili ang pokus at magsikap sa iyong ginagawa, at magkakaroon ka ng isang matagumpay na karera sa kabuuan ng iyong ginagawa. Sino ako: Napagtanto ko na ang huling seksyon ay higit pa tungkol sa pag -aaral at ang iyong mga paraan mula sa aklat na ito. Sino ako eksakto? Iyon ay isang kumplikadong tanong. Hindi ako malinaw sa aking sarili, habang nagdurusa ako sa mga kondisyong medikal na maaaring maging mahirap para sa akin kahit na code o isulat ang aklat na ito minsan, habang ipinapakita ang mga hamon na may mga isyu sa pagsasapanlipunan at pagkakakilanlan na nagpapahirap sa aking buhay pagdating sa pagpapakilala sa aking sarili . Sa madaling sabi, kung binabasa mo ang librong ito, dinala mo ito sa bahay dahil na -flip mo ito at naisip na kapaki -pakinabang ito, o kahit na nabasa mo lang ito, sa iyo ako ay isang katulad na indibidwal na nais na makita kang magtagumpay sa lahat ng ginagawa mo. Ako ay isang inhinyero mismo,nag -develop, at isang mag -aaral, at isinusulat ko ang librong ito para sa iba pang mga mag -aaral na nais na gawing mas madali ang kanilang buhay sa pamamagitan ng pagkakaroon ng isang handbook ng software na kailangan nilang gawing mas madali ang kanilang buhay sa pamamagitan ng pagbibigay ng mga halimbawa upang kopyahin na magkakasama tulad ng isang malaking palaisipan sa isang nagtatrabaho , kapaki -pakinabang, malaki, pag -andar, cohesive, at nakakaengganyo na app na maaaring magmaneho ng tagumpay kahit na ang linya ng negosyo. Lalo na, ito ang ginagawa ko: Nagtatayo ako ng mga app upang matulungan ang aking sarili at ang ibang tao ay magtagumpay. Ako rin ay isang may -akda, kahit na ito ang aking unang publikasyon na balak kong makumpleto upang magkasama ang aking portfolio sa isang kapaki -pakinabang na dokumento, at ako ay isang artista din. Aaminin ko ito sa iyo, ako ay uri ng isang kakaibang tao. Hindi ako perpekto, pinatakbo ko ang INS kasama ang batas kahit na humahantong sa akin na mag -iwan ng mga kolehiyo at unibersidad at mag -iwan ng mga estado upang subukang gumawa ng isang pangalan para sa aking sarili na may higit na tagumpay. Ako ay isang babae sa pamamagitan ng kapanganakan, nagsusuot ako ng pampaganda, kumuha ng litrato ng aking sarili, magsuot ng damit at iba pang damit ng mga kababaihan, at nananatili akong may kamalayan sa aking sarili bilang isangBabae ayon sa kalikasan. Nagkaroon ako ng mga isyu sa ibang mga tao sa nakaraan na humantong sa mga pakikibaka sa pagsulat at pagbuo ng mga webapp, at humihingi ako ng paumanhin na hindi ko pa nakuha ang aklat na ito sa iyong mga kamay nang mas maaga: kailangan mo ito. Gusto mong basahin at isulat ang code na katulad ng minahan at gumagana tulad ng minahan at ginagawa ang parehong bagay ngunit mas mahusay, dahil kung makakaya mong bilhin ang librong ito sa halip na mashing ang iyong keyboard tulad ng ginagawa ko upang lumikha lamang ng isang libro sa iyong sarili na humihiling ng pera Para dito, mayroon kang mga mapagkukunan na kailangan mong maging matagumpay sa iyong buhay. Nagkaroon ako ng lahat ng uri ng mga isyu sa paglaki ng pamilya, mga kondisyon ng kalusugan, mga doktor, media, at batas, at ang aking code ay malalim na sumasalamin sa pakikibaka na pagkababae at babaeng kalikasan sa isang nahahati at bigo na mundo. Gayunpaman, ang librong ito ay isang bagay na labis kong pinapahalagahan, ang aking sanggol, ang aking portfolio, at ang aking kabuhayan, kaya pinahahalagahan ko ang iyong pagsasaalang -alang kapag kinuha mo ang teksto sa bahay at maingat na sinimulan ito upang malaman mula sa akin. Mangyaring tandaan na hindi akoect, ang aklat na ito ay magkakaroon ng mga pagkakamali, pagbabago, at mga bagong edisyon, at kakailanganin mong mag -isip sa iyong lohikal na utak hangga't maaari upang magkaroon ng isang matagumpay na karanasan sa aking pagsulat. Gayundin, maunawaan na ang ibig kong sabihin ay mabuti para sa iyo kahit na nahaharap ka sa mga hamon kapag nagsusulat. Isipin ito tulad nito: Kapag maaari ka lamang magrenta ng isang computer system upang gawin ang anumang maaari mong isipin sa digital na puwang, itabi ang lahat ng impormasyong nakatagpo mo, #$%! Yze at ayusin ito, at maunawaan mo ito, gagawin mo Hindi maiiwasang makatagpo ng mga paghihirap sa impormasyong iyong ingesting at kahit na pag -publish. Sinasabi ko ito sa iyo dahil nakatagpo ako ng parehong mga paghihirap. Gamitin ang librong ito sa iyong sariling peligro, makipagtulungan sa iyong komunidad at mga komunidad na magagamit mo upang makabuo ng software sa loob ng isang ligtas na setting, at huwag kumuha ng mga bagay nang personal kapag nabigo ka o kahit na magtagumpay sa maling paraan: ganyan ang nakuha ko sa ngayon , at kung bakit maaari kong dalhin sa iyo ang tekstong ito at tulungan kang magtagumpay nang walang pag -iiba sa isang landas ng kabaliwanAng Aves Me wasak, napunit at nag -fray habang nakatagpo ako ng mga ordinaryong problema na ginagawa ng lahat sa isang pandaigdigang sukat salamat sa paralellistic global scale ng network kung saan tayo gagana, ang Internet. Maaaring hindi ka masyadong pamilyar sa kung sino ako sa ilang mga salita, ngunit hinihikayat ko kayong basahin, makikilala mo ako habang patuloy kang nagbabasa at nauunawaan ako habang nagtatayo ng iyong sariling mga proyekto upang makumpleto ang iyong trabaho. Hindi magkakaroon ng araling -bahay sa librong ito, hangga't ang iyong mga propesor o guro ay hindi magtatalaga sa iyo ng anuman, ngunit lubos kong hinihikayat ka na magtayo ng isang portfolio ng mga proyekto sa iyong sarili habang binabasa mo, pati na rin ang isang proyekto ng capstone na nagpapakita kung paano mo magagawa Ilapat ang natutunan mo. Ang aking proyekto sa Capstone ay ang batayan para sa karamihan ng iyong babasahin sa aklat na ito, dahil isinasama nito ang code mula sa aking mga nakaraang proyekto, code na nilikha ko at natutunan na sumulat ng pamamaraan sa pamamagitan ng kamay, at isang malawak na hanay ng mga ideya at tip na nakatulong sa akin magtagumpay sa punto kung saan maaari kong paikutin ang isang simpleng app naGanap na itinampok at hitsura at kumikilos tulad ng isang tanyag na app na maaari mong makita ang iyong kaibigan o pamilya na ginagamit, sa internet, na -advertise sa iyo, o sa balita. Ano ang aklat na ito: Ang librong ito ay isang tutorial sa pamamagitan ng halimbawa. Maaari kang makahanap ng code dito, mga tagubilin para sa kung paano matutong mag-code, impormasyon sa pag-debug ng code at pag-aayos ng mga error, mga hakbang sa pag-aayos, mga tagubilin sa kung paano i-back up at i-save ang iyong code, muling deploy kung may sinira ang iyong code, secure ang iyong code, mag-deploy Ang iyong code, bumuo ng mga interactive na website na nakakaaliw, nakakaengganyo, at nakakahumaling, at makakakuha ka ng isang kahulugan kung sino ako, kung bakit mahalaga ito, at kung paano ilarawan ang iyong sarili, ang iyong app at imahe ng kumpanya, pati na rin ang software Nagtatayo ka sa ganap na pinakamahusay na ilaw upang maging pinaka -kaakit -akit hangga't maaari sa iyong mga end user, ang mga bisita ng iyong website. Sa librong ito, magpapakita ako ng isang bilang ng mga halimbawa ng disenyo ng software na may pagtuon sa web bilang isang platform pati na rin ang seguridad. Sisimulan namin ang karanasan sa pag -aaral sa pamamagitan ng pagbuo ng isang pangunahingOject gamit ang UNIX shell, na may mga backup at tampok na script. Pagkatapos, susuriin namin ang isang pangunahing website ng blog, i -upgrade ang aming blog na may mga tampok ng larawan at video pati na rin gamitin ang mga tampok na ito upang gumamit ng mga solusyon sa seguridad gamit ang libreng software, at ma -secure ang aming server gamit ang isang Module ng Pluggable Authentication (PAM). Susuriin namin pagkatapos ang paghawak ng file at pagproseso, paggalugad ng pag -edit ng video, donasyon ng boses, pag -scan ng barcode at pagkilala sa optical character, bukod sa iba pang mga konsepto. Kasabay ng susuriin natin ang mga API na makakatulong sa amin na gawing mas kapaki -pakinabang at ligtas ang aming software, na may libre at bayad na mga pagpipilian. Kasabay nito, galugarin namin ang pisikal na seguridad at militanteng mga tool tulad ng disenyo ng mga baril at munisipyo at pagmamanupaktura kabilang ang disenyo ng bariles at repeater, disenyo ng turret at drone, at iba pang mga punong -guro na isasama namin sa aming software sa umiiral na network upang maprotektahan ang aming software at ipakita ang pagtatanggol sa sarili at pagiging matatag. Magpapahinga kami sa daan upang makabuo ng mga laro, 2d at 3dAng mga endering engine, at nagtatrabaho sa naka -embed na hardware sa kaso ng pag -aaral ng mga halimbawa ng pangunahing dimensional na pag -render ng software at isang electronic vibrating massager cast sa silicone goma ayon sa pagkakabanggit. Kasabay nito, magagamit din namin ang mga solusyon sa pag -aaral ng machine na magagamit upang mas mahusay na ma -secure ang aming software. Gumagamit din kami ng mga tool sa stock na magagamit para sa web upang mai -streamline at ma -secure ang proseso. Ang librong ito ay isang gabay sa iyong tagumpay sa pagbuo ng isang web application at pagsasama nito sa isang propesyonal na network ng computer at naka -embed na mga mekanikal na sistema, at pangkalahatang isang gabay sa pagbuo ng software at naka -embed na hardware na walang kaalaman sa background o nakaraang karanasan. Ano ang aklat na ito ay hindi: Kung talagang nais mong magkaroon ng isang website, maaari ka lamang mag -set up ng isang simpleng tindahan at ibenta ang kailangan mo, mag -post ng isang blog, mag -post ng mga larawan o video, o kung hindi man nang hindi nagsusulat ng isang linya ng code. Ang librong ito ay hindi iyon. Tuturuan ka ng librong ito kung paano bumuo ng software na mas kapaki -pakinabang, ganapItinampok, functional at secure kaysa sa anumang software na maaari mo nang mahanap, dahil ipinapadala nito ang pinakabagong software na pa rin mga prototypes, maaaring mamahaling tumakbo sa isang scale na mas matatandang kumpanya na gumana, at hindi apila sa paatras, pinagsama -samang mga kumpanya na naka -set up sa Kumita ng pera para sa mga taong wala talagang ginagawa. Kung susundin mo nang mabuti ang librong ito, nais mong magsulat ng code, code ng pananaliksik, bumuo ng iyong sariling mga app, at makakakuha ka ng pera mula sa iyong ginagawa. Gumagawa ako ng pera mula sa librong ito, kahit na sa mga unang yugto, sapagkat naglalaman ito ng impormasyong kailangan ng mga tao at nais na basahin, at bumibili na sila kapag binili o ginagamit nila ang aking mga app. Ang librong ito ay hindi magtatayo ng isang app para sa iyo, ngunit ituturo ka nito sa tamang direksyon at braso ka ng mga tool na kailangan mo at ang mga kasanayan at mga tip na mapadali ang iyong sariling tagumpay sa pagbuo ng software para sa web, sa bawat linya ng Code kakailanganin mong sumulat bilang isang halimbawa, handa nang magkasama sa software na ikaw at ang iyong mga tagasuporta, panauhin, kliyente,Ang mga riends, pamilya, bisita, kontratista, at ang mga tao sa Internet ay nais gamitin at suportahan. Ano ang matututuhan mo: Ituturo sa iyo ng librong ito kung paano bumuo at magbenta ng software, talagang functional, kapaki -pakinabang na software, pag -record ng media, mga tampok ng seguridad tulad ng pagkilala sa facial, machine na mababasa na zone barcode scan, mga web API upang mapatunayan, mag -record at mag -render ng video at mga larawan, at mga mensahe ng palitan tulad ng Bluetooth at malapit sa Field (NFC) na komunikasyon. Ituturo sa iyo ng librong ito kung paano gumamit ng isang network na computer, na nakatuon sa debian Linux, kung paano bumuo ng bash code upang makagawa ng pag -install at pag -back up ng iyong software ng isang walang tahi, awtomatikong simoy, kung paano bumuo ng code ng python bilang isang backend upang maghatid ng mga dynamic na mensahe, estilo Ang mga bagay na mahusay na gumagamit ng mga estilo ng CSS na may bootstrap, paganahin ang mga logins ng gumagamit at pakikipag -ugnay sa pamamagitan ng mga aparato na may network, bumuo ng interactive na media at network sa iba pang mga website upang mag -alok ng mga tampok ng seguridad tulad ng mga text message para sa pag -verify o iba pa Mga layunin, pag -scan ng ID, pag -moder ng imahe at video, dataMga ransaksyon upang mapanatili ang iyong software na ligtas, pagproseso ng pagbabayad, pangangalakal ng cryptocurrency, mga gawain na hindi sinasadya, at marami pa. Malalaman mo kung paano bumuo ng iyong sariling mga aparato ng Bluetooth, na may mga baterya, charger, microcontroller, circuit, motor at sensor, gamit ang panghinang, wire at 3D na nakalimbag pati na rin ang mga materyales sa cast. Ipapakita ko ang mga punong -guro ng disenyo ng 3D na inilalapat sa additive manufacturing at tool at die paggawa, kaya nagagawa mong gumawa ng iyong sariling naka -embed, mga aparato ng hardware na may mga pinagsamang baterya, charger, electronic circuit, at functional output. at i -network ang mga ito sa Bluetooth at sa web. Partikular, susuriin natin ang dalawang pag -aaral sa kaso, isang panginginig ng massager at isang gawang bahay na baril, na parehong na -program sa OpenScad, na magagamit bilang isang graphical interface o utility ng linya ng linya at maaaring maisama sa isang web para sa mga resulta ng bilis. Malalaman mo kung paano bumuo at mag -deploy ng isang website mula sa ground up na walang naunang karanasan, gawin itong functional, secure, maganda, kapaki -pakinabang at karamihanpraktikal na praktikal. Malalaman mo kung paano gamitin ang pag -aaral ng machine at pangitain sa computer upang gawing ligtas at mas praktikal ang isang site, mag -record ng video at audio mula sa iyong website, ibigay ang iyong boses, gumawa ng musika at baguhin ang audio upang lumikha ng mga kapaki -pakinabang na halimbawa, at kung paano masira ang ingay sa pamamagitan ng Pag -agaw ng iba pang mga website upang mabuo ang pinakamahusay na posibleng network ng mga website na maaari mong mai -link nang direkta sa iyo upang maibahagi ang lahat ng mga kapaki -pakinabang na impormasyon na mayroon ka upang mag -alok, at kahit na mas mahalaga na dalhin ang mga tao sa iyong software at negosyo. Ang librong ito ay mas nakatuon sa media, seguridad at pag -aaral ng makina, na siyang pangunahing tatlong sangkap na makakatulong sa iyo na bumuo ng kapaki -pakinabang na software para sa web sa pamamagitan ng pagsali sa mga tamang gumagamit at pag -disengaging mga mali sa isang paraan na makatotohanang, praktikal, mga kamay at nakakaengganyo habang awtomatiko, at matibay. Itinuturo ng aklat na ito ang Unix, partikular na Debian (Ubuntu), Bash Shell, Python, HTML, CSS, JavaScript, at isang bilang ng mga kapaki -pakinabang na pakete ng software para satulad ng mga kahilingan, pati na rin ang kapaki -pakinabang na software ng bash tulad ng git at ffmpeg. Tuturuan din kita kung paano awtomatikong ipagpalit ang cryptocurrency, at kumuha ng mga pagbabayad sa cryptocurrency o mula sa regular na mga debit card habang binabayaran ang iyong mga bisita ng isang bahagi ng iyong kita kung pipiliin mong gawin ito. Ituturo ko sa iyo kung paano kumita ng pera mula sa iyong website sa pamamagitan ng advertising din, kung paano ihanda ang iyong app para sa mga search engine at gawin itong mabilis, na na -ranggo sa unang pagraranggo para sa kung ano ang hahanapin ng iyong mga customer upang mahanap ka, at mag -ranggo ng maraming karaniwan mga paghahanap hangga't maaari. Ituturo ko sa iyo kung paano ibenta ang iyong software, i -advertise ito, mag -apela sa mga kliyente na naghahanap ng iyong mga serbisyo, at gumawa ng isang pangalan para sa iyong sarili sa internet sa pamamagitan ng mga avenues na mayroon na, ay mura, at gumana nang maayos. Ituturo ko sa iyo kung paano i -save ang iyong data sa mga computer ng ulap na gumagana para sa iyo at i -save ang iyong data nang mura, kung paano magplano at bumuo ng isang website na ginagawa kung ano ang nais ng iyong mga gumagamit at kung ano ang gusto mo, at kung paano panatilihin ang iyong mga gumagamit na makisaliAng iyong site ay isang gripo sa kanilang mga telepono na may mga abiso, email, mga text message, tawag sa telepono, at higit pang mga paraan upang maibalik ang iyong mga gumagamit sa iyong website sa iyong pagtatapon sa likod ng pag -click ng isang pindutan na na -secure sa iyo lamang. Ang aklat na ito ay tututuon sa pagiging praktiko ng pag -publish at pamamahagi ng media sa maraming halaga, mula sa teksto hanggang sa mga larawan hanggang sa mga video hanggang sa audio, paggawa ng isang mahusay na impression sa mga end user (iyong kliyente), at pagbebenta ng iyong sarili sa anumang paraan na ginagawa mo upang lumikha Ang isang website, isang app na kinatawan mo at ikaw lamang, at ginagawa ka, ang iyong software at ang iyong kumpanya ay maganda sa pinakamahusay na paraan na posible. Malalaman mo rin ang ilang mga tip at trick mula sa akin, mula sa mga tip sa pag -cod, praktikal na walang kabuluhan tulad ng pampaganda at pagkuha ng litrato, pagmomolde at kumikilos, at higit pa, na magiging mahalaga para sa paglalarawan ng iyong sarili at sa iyong kumpanya sa pinakamahusay na posibleng ilaw gamit ang lahat ng mga tool na magagamit sa iyo habang namamahagi ng maraming nilalaman hangga't kailangan mo sa isang malusog na balanse ng mga platform upang dalhin ang iyonge na magbunga nang walang mas pagsisikap, trabaho, o pera kaysa sa kinakailangan. Ang aklat na ito ay tinatawag na "Practical Web Based Deep Learning and Security sa pamamagitan ng Halimbawa" para sa isang kadahilanan: Nakikipag -usap ito sa pag -aaral sa code, partikular para sa web, partikular na may pagtuon sa seguridad, mula sa isang praktikal na paninindigan, na may mga halimbawa ng nagtatrabaho code na nagsisilbi Ang mga praktikal na layunin na nakabalangkas sa teksto. Ang sangkap ng pag -aaral ng tekstong ito ay sumasaklaw din sa pag -aaral ng machine, ang code na ipapakita ko sa iyo kung paano tumakbo para sa web na hahawak sa paningin ng computer, pagkilala sa mukha, pag -moderate ng imahe at video, pagpapahusay ng imahe, pagpapahusay ng resolusyon, pag -caption ng imahe, at iba pang mga gawain tulad ng Ang mga sukatan ng hula na nagmula sa mga imahe, tulad ng likas na katangian ng imahe bilang isang tunay, imahe na inilipat ng computer, o isang optical na kopya (isang larawan ng isang imahe, o nakalimbag na larawan). Napakahalaga ng pag -aaral ng makina pagdating sa seguridad sa web at software ng seguridad, dahil maaari itong mag -preform ng mga gawain na kung hindi man imposible. Ang iyong computerMag -log ka sa isang passcode, ngunit maaaring mas ligtas na gamitin ito kung nag -log ka sa iyong mukha. Maaari kang gumawa ng isang computer ng server na ito ay ligtas, isang computer na karaniwang hihilingin sa iyo para sa isang username at passcode at mag -log in ka, marahil sa isang token ng kumpirmasyon para sa bawat bagong pag -login o bagong IP address, ngunit kung nagtatayo ka ng malaking sukat, madali Gumamit, panimula na ligtas, at malakas na software, maaaring ito ay sapat. Ang pagtali ng iyong software ay masyadong malapit sa software ng ibang tao, tulad ng isang serbisyo sa email o serbisyo ng text message, ay hindi sapat upang ligtas ang iyong software, o sinuman (anumang site na ginagamit mo). Ang sinumang nagtatayo ng software na hindi maiiwasang ligtas ay may ilang kahulugan sa kung ano ang ipinahihiwatig nito. Ang software ay likas na hindi sigurado dahil ang mga aparato at account na ginagamit namin upang ma -access ito ay hindi palaging nasa aming pagtatapon, maaari silang nasa kamay ng sinumang may masamang hangarin para sa software at sa gayon ay maaaring magdulot ng isang panganib sa software mismo. Ito ay isang bagay ng pokus ng aklat na ito. Ang isang network na computer ay sa pamamagitan ng defaultNa -secure na may isang mahabang key token, tinawag at SSH o Secure Shell key, at kung hindi man ay pinakamahusay na na -secure sa isang web server, dahil ang web server ay nagbibigay ng bukas na pag -access pati na rin ang estado ng mga tool sa seguridad ng sining na tumatakbo sa server mismo. Ang web server ay may access sa web browser ng gumagamit, na kung saan ay maaaring ang pinakamalakas na bahagi ng aparato ng gumagamit, dahil ito ang lugar kung saan ma -access ng gumagamit ang network na software. Ang toolkit na ito ay maaaring mag -render ng teksto, ang mga webpage na nakikita mo, at maaari ring magrekord ng mga imahe, audio at video (tulad ng isang larawan ng isang mukha o isang estado ng ID), ay maaaring basahin at isulat sa mga aparatong radyo ng Bluetooth, at maaaring basahin at isulat sa Malapit na Patlang Mga tag ng transponder, murang mga key card, fob, sticker, singsing at kahit na mga implant ng chip na may natatanging mga serial number na maaaring mabasa at isulat sa data na nabuo at napatunayan ng isang web server na nakatali sa web site. Gamit ang lahat ng mga tool sa iyong pagtatapon, kasama ang librong ito ay bibigyan mo ng kasangkapan ang iyong sarili sa kaalaman upang makabuo ng isang ligtas na website, at pangkalahatang aAng sistema ng computer na naka -network na gumagana para sa iyo, ginagawa ba ang iyong pag -bid, at hitsura at pakiramdam ng tama. Saan magsisimula: Malugod kang lumaktaw sa seksyon na sinimulan ko ang librong ito, o anumang seksyon, sa eksaktong code na kailangan mo, lalo na kung mayroon kang karanasan sa pag -cod bago o alinman sa nabanggit na mga tool ay ilalarawan ko nang detalyado sa aklat na ito bilang pati na rin ang pagdodokumento ng mga kaso ng paggamit at praktikal na mga halimbawa nito. Kung wala kang karanasan sa pagsulat ng code, lubos kong inirerekumenda na basahin mo ang lahat ng aklat na ito, at lalo na inirerekumenda na basahin mo ang mga nakaraang seksyon, upang matiyak na tama ang aklat na ito para sa iyo. Kung ang aklat na ito ay hindi tama para sa iyo, isaalang -alang ang pagbago nito sa isang kaibigan o kamag -anak na maaaring interesado na malaman ang tungkol sa pag -unlad ng web, at isaalang -alang ang paghiram nito at pag -aaral mula sa kanila upang punan ang mga gaps kung saan nabigo kita bilang isang Guro, o iba pang mga guro sa harap ko. Simulan kung saan ka, ang bawat bahagi ng aklat na ito ay magiging kapaki -pakinabang kung balak mong bumuo ng isang kapaki -pakinabangPP, at isaalang -alang na ang pinakamahusay na mga app ay binuo gamit ang end user sa isip: alamin ang iyong customer. Ngayon kilala mo ako, alam mo ang librong ito, at handa ka nang magsimula. Upang magsimula, kumuha ng isang computer (kahit na ang pinakamurang laptop mula sa isang tindahan ng kahon, Amazon, o isang lumang desktop ay gumagana, at itakda ito sa isang paraan na gumagana para sa iyo. Paano basahin ang librong ito: Ang naka -highlight na teksto, nagsasaad na ang teksto ay kabilang sa isang command prompt, kung saan isusulat mo ang code na iyong pinapatakbo. Ang command prompt ay mabigat na keyboard na nakatuon at nangangailangan ng kaunti upang walang pag -click, pabilisin ang iyong daloy ng trabaho at gawing mas madali ang mga bagay sa iyo. Pagsisimula: Sumisid tayo. Magsisimula kami sa pamamagitan ng pagbuo ng code sa isang lokal na makina at magsimula nang hindi nagtatayo ng isang website na konektado sa internet. Ito ay mas ligtas upang magsimula sa, walang gastos, at madali para sa iyo. Depende sa iyong operating system, ang pagpasok sa isang bash shell ay medyo naiiba. Para sa Mac OS, inirerekumenda kong mag -install ng isang virtual machine sa puntong ito, dahil makakakuha ka ng pinakamaraming pagiging tugmaVirtual machine. Ang iba't ibang mga tagapagkaloob tulad ng VirtualBox at Paralells ay maaaring magpatakbo ng isang virtual machine para sa iyo, kahit na posible ring i -install nang direkta ang Ubuntu sa makina, kung mas gusto mong gumamit ng isang katutubong kapaligiran na inirerekomenda upang lumikha ng isang mabilis, naka -streamline na karanasan. Kung gumagamit ka ng Linux o Windows, na inirerekumenda ko, dapat itong madaling lumikha ng isang proyekto. Buksan ang iyong terminal, ayusin ang sizing tulad ng nakikita mong akma, at simulan ang pagsunod sa Hakbang 2. Kung gumagamit ka ng mga bintana, mangyaring sundin ang Hakbang 1. Hakbang 1: - Mga gumagamit ng Windows lamang Sa Windows, bukas na utos ng command bilang administrator at uri WSL -Install Hakbang 2: - Magpatuloy dito, o laktawan ang Hakbang 1 hanggang dito kung hindi ka gumagamit ng Windows Sa isang bukas na terminal, (depende sa iyong OS, na tinatawag na Ubuntu sa Windows, terminal sa Mac o Linux, o isang katulad na pangalan), magsimula sa pamamagitan ng paglikha ng isang proyekto. Ginagawa namin ito sa utos ng MKDIR, na lumilikha ng isang direktoryo. Kung kailangan mong lumikha ng isang direktoryo upang maiimbak ang iyong proyekto, na inirerekomenda, gamitin angutos ng cd na magbago sa direktoryo at at CD/PATH/TO/DIRECTORY - Ang landas ay ang mga folder (mga file) na nauna sa iyong direktoryo ng patutunguhan, ang iyong default na landas ay ~ o/home/username (kung saan ang username ang iyong username). Upang magbago sa default na direktoryo, i -type ang CD o CD ~ Halimbawa ng MKDIR - Palitan ang "halimbawa" sa pangalan ng direktoryo Ngayon mayroon kang isang direktoryo ng pagtatrabaho para sa iyong proyekto. Ang pagiging napakahalaga na mai -save ang direktoryo na ito kung sakaling kailangan mong lumipat sa ibang makina o i -deploy ang code na isinulat mo kaya handa na ito para sa web, magtatayo kami ng isang script upang mai -back up ang iyong direktoryo sa susunod na ilang mga hakbang. Ngunit ang pagbuo ng isang script ay tumatagal ng kaunting code, at ang code ay kailangang awtomatiko upang maging kapaki -pakinabang hangga't maaari. Kaya magtayo tayo ng isang script upang magtayo muna ng mga script. Magsimula tayo sa pamamagitan ng paglikha ng script at gawin itong maipapatupad. Gumagamit kami ng sudo, chmod at hawakan para dito, at tawagan ang script


sudo touch /usr/bin/ascript
sudo chmod a+x /usr/bin/ascript
sudo nano /usr/bin/ascript
Ngayon nilikha namin ang script, ginawa itong maipapatupad, at handa nang i -edit ito. Ang Nano ay isang text editor na hahayaan kang mag -edit ng teksto nang hindi nag -click, na mas madali kaysa sa paggamit ng isang interface ng graphic na gumagamit. Upang mai -edit ang isang file na may nano, gumamit ng nano at pagkatapos ay ang landas sa file. Upang makagawa ng isang script na gumagawa ng isang script, medyo katulad ito sa paggawa ng aming script sa unang lugar. Gagamitin namin ang parehong code tulad ng nasa itaas, na pinapalitan ang pangalan ng script, "ascript" na may parameter ng argumento, $ 1. Pinapayagan kaming tawagan ang script sa pamamagitan ng pag -type ng simpleng sudo ascript newscript, sa puntong ito maaari kaming lumikha ng anumang bagong script sa pamamagitan ng pagpapalit ng "Newscript" sa pangalan ng iyong script. Ang code sa nano ay dapat magmukhang:

sudo touch /usr/bin/$1
sudo chmod a+x /usr/bin/$1
sudo nano /usr/bin/$1
At upang isara ang nano, maaari nating pigilan ang control key at pindutin ang x, pagkatapos ay y upang ipahiwatig na nai -save namin ang file, at pindutin ang pagbabalik. Ngayon sa halip na i -type ang tatlong mga utos na ito upang mai -edit ang isang script, magagawa nating mag -type ng sudo ascript ascript upang mai -edit muli ang script. Gumagana ito! At ang anumang bagong script ay maaaring tumakbo nang madali sa pamamagitan ng pagtawag nito sa shell. I -save natin ang aming trabaho ngayon: Sumulat tayo ng isang backup script upang mai -save ang aming bagong script at pagkatapos ay i -back up ito sa aming direktoryo ng proyekto, habang sinusuportahan din ang backup script.

sudo ascript backup
Now, in nano:

sudo cp /usr/bin/backup /path/to/directory/
sudo cp /usr/bin/ascript /path/to/directory/
Kung saan/path/sa/direktoryo ay ang landas sa proyekto na nilikha mo kasama ang MKDIR. Mamaya matututunan natin kung paano kopyahin ang mga paulit -ulit na landas na tulad nito na may isang loop at isang listahan, na hindi gaanong code, ngunit sa ngayon panatilihin itong simple at magkaroon ng ilang mga linya. Upang patakbuhin ang script na ito at i -backup ang iyong code, i -save ang file sa nano na may control+x, y at bumalik, at i -type ang ibaba sa iyong shell

backup
Kung sinenyasan ka ng lahat para sa isang password habang binabasa ang librong ito at sumunod sa shell, mangyaring ipasok nang tama ang iyong password ng gumagamit, magkakaroon ka ng tatlong pagsubok bago mo kailangang muling patakbuhin ang utos. Maaari mong gamitin ang pataas at pababa na mga arrow upang mag -rerun ng mga utos at i -edit ang mga ito, dapat mong kailanganin ang anumang bagay nang dalawang beses. Simpleng pindutin pataas at pababa nang paulit -ulit upang pumili ng isang utos, bago i -edit ang utos gamit ang kanan, kaliwang arrow at tanggalin ang key pati na rin ang keyboard, at pinapatakbo ito nang may pagbabalik. Binabati kita! Pinamamahalaang mong lumikha ng isang kahanga -hangang script ng backup na sumusuporta sa dalawang mahahalagang script ng shell sa iyong direktoryo ng pagtatrabaho. Maaari naming ilipat ang mga bagay sa paglaon habang ang proyekto ay nagiging mas malaki, ngunit ito ay gumagana para sa ngayon. Lumipat tayo sa pag -back up sa ulap, gagamitin namin ang GitHub para dito (kahit na maraming iba pang mga solusyon sa git para sa pag -backup, lahat sila Software habang ginagawa mo ang mga ito sa isang server, habangPinapagana ka rin upang i -download ang buong mga kopya ng iyong software sa likod ng isang password o key. Ito ay nakatulong sa pag -save ng iyong software, lalo na habang lumilipat kami sa mga secure na mga pagkakataon sa Linux na kung minsan ay masisira kapag nabigo ang isang solong linya ng code, iniwan kang naka -lock habang ang iyong code ay maaaring hindi mai -back up kung hindi ka makakakuha ng isang pagkakataon upang mai -back ito Awtomatikong, na tatalakayin namin. Kung hindi ka pa gumagamit ng isang ubuntu virtual machine sa puntong ito, nag -reccomend ako gamit ang isang ubuntu virtual machine sa puntong ito sapagkat mas madali ang iyong buhay kapag mai -install ang lahat ng mga pakete na kinakailangan upang makabuo ng isang gumaganang website at preform malalim na pag -aaral operasyon sa iyong computer. Ililipat namin ang code sa isang web server sa malapit na hinaharap, ngunit nais naming tiyakin na may hindi bababa sa ilang mga layer ng seguridad sa likod ng aming web server na lumalaban sa phishing, at gumamit ng isang bilang ng mga pakete ng Linux upang magawa ito Kung nais mo pa ring gumamit ng Mac OS, malugod kang maghanap at mag -installe kinakailangang mga pakete sa online, ngunit maaaring walang mga kahalili para sa bawat pakete na saklaw ng aklat na ito o serye. Magdagdag tayo ng ilang mga utos upang gawin ang aming gawain sa backup script sa pamamagitan ng pagpapatakbo ng command sudo ascript

# …
git add –all
git commit -m “backup”
git push -u origin master
Muli, kontrolin ang X upang makatipid. Ngayon kailangan nating gawin ang isang oras na pagsasaayos para sa proyektong ito. Dahil sa lalong madaling panahon ay magiging isang proyekto ng git, hindi natin kailangang i -type ang bawat utos sa tuwing mag -deploy tayo mula sa isang imbakan ng git, ngunit kukunin natin ang hang nito kapag isinulat namin ang aming mga script ng pag -deploy. Upang magsimula, tiyakin na nasa tamang direktoryo tayo at simulan ang pag -iimbak ng git at makabuo ng mga susi ng SSH.

cd /path/to/directory
git init
git branch -m master
ssh-keygen
Matapos naming i-type ang SSH-Keygen, ang bagong susi ay dapat mai-save sa folder ng bahay sa ilalim ng isang folder na tinatawag na .ssh. Ito ay tinatawag na ID_RSA.pub. Hanapin natin ang susi na ito at kopyahin ito. Upang makita ito,

cd ~
cat .ssh/id_rsa.pub
Kopyahin ang teksto na ibabalik ng huling utos, at lumikha ng isang account gamit ang iyong GIT provider (perpektong github), bago idagdag ang SSH key sa iyong account. Kapag mayroon kang isang account, i -click ang kanang kanang menu at ipasok ang mga setting, bago idagdag ang iyong SSH key sa SSH at GPG key sa ilalim ng pag -access sa menu. Piliin ang Magdagdag ng isang SSH key at idagdag ang iyo sa pamamagitan ng pag -paste nito at bigyan ito ng isang pamagat, bago i -save at bumalik sa GitHub upang lumikha ng isang bagong imbakan. Ito ay katulad ng iba pang mga nagbibigay ng git, kakailanganin mong basahin ang kanilang dokumentasyon. Sa bagong pagsasaayos ng imbakan, bigyan ang iyong imbakan ng isang naglalarawang pangalan at magpasya kung nais mong mai -publish ito, at tiyaking i -configure ang wala pang mga file para sa pagsasama. Kapag nilikha ang imbakan, kopyahin ang clone na may SSH URL, at i -paste ito sa sumusunod na utos.

git remote add git://… (your remote URL)
Ngayon ay maaari kang bumalik sa iyong imbakan sa CD, pamilyar ka dito. Subukan ang iyong backup script ngayon na may backup Mahusay! Ngayon ay maaari talaga tayong makakuha ng coding. I -install natin ang Django ngayon na mayroon kaming isang mahusay na pagkaunawa sa bash at git. Hahayaan tayo ni Django na awtomatikong i -back up ang aming software, magagawa din ito ni Bash ngunit ang Django ay dapat magkaroon ng isang mas simpleng mas ligtas na pagpapatupad (maaari itong hindi paganahin at mas madaling ma -configure). Upang mai-install ang software sa Ubuntu, gagamitin namin ang utos ng sudo apt-get. Una, i -update natin at i -upgrade ang software na mayroon tayo. Maaari itong gawin sa pag-update ng sudo apt-get at sudo apt-get upgrade -y. Susunod, i-install natin ang Python at ang aming virtual na kapaligiran, ang tahanan ng aming code, kasama ang sumusunod na utos: sudo apt-get install python-is-python3 python3-venv Ito ang kailangan mo upang makakuha ng pagpunta sa Django sa mga tuntunin ng mga pag -install ng software sa halimbawa ng Ubuntu. Para sa Windows at Linux ito ay dapat na medyo prangka, ngunit para sa Mac baka gusto mong mag -install ng isang virtual machine atAng Linux dito gamit ang isang libre o bayad na virtual na kapaligiran tulad ng VirtualBox o Paralells Desktop at muling likhain ang mga hakbang sa itaas upang mag -setup ng isang kapaligiran ng Ubuntu. Ang Ubuntu ay kritikal sa kasong ito sapagkat ito ang software na tumatakbo ang mga website at pinapayagan silang mag -host ng mga website na may lahat ng nabanggit na software. Humukay tayo sa Django. Sa aming direktoryo muli, kasama

python -m venv venv # Lumilikha ng virtual na kapaligiran kung saan naka -imbak ang code
source venv/bin/activate # Isinaaktibo ang virtual na kapaligiran
pip install Django
django-admin startproject mysite . # Kung saan ang Mysite ay ang proyekto na nagsisimula ako sa aking kasalukuyang direktoryo.
Sinimulan lang kami ni Django, dahil ang Django ay nagho -host sa web server at ginagawa ang lahat ng kailangan namin upang makakuha ng isang pangunahing lokal na website at tumatakbo. Ngayon na na -install namin si Django, i -edit natin nang kaunti ang mga setting upang gawin itong gumana kung paano natin kailangan. Una, lumikha tayo ng isang bagong app

python manage.py startapp feed
Mapapansin mo ang unang app ay tinatawag na feed. Ang app ay dapat tawaging anuman ang gusto mo, at gagawa kami ng mga bagong app, ngunit ang pangalan ng bawat app ay dapat na pare -pareho sa bawat oras na ang app ay na -refer sa code. Upang magdagdag ng isang bagong app, lagi naming mai -edit ang mga setting.py sa iba pang direktoryo na nilikha ng app, na pinangalanan sa StartProject, pagkatapos ng app. Gamit ang nano,

nano app/settings.py
Sa mga setting, maghanap ng mga naka -install na_apps at paghiwalayin ang [] sa 3 linya. Gamit ang apat na puwang sa linya ng walang laman na sentro, magdagdag ng 'feed', o ang pangalan ng iyong app. Ang seksyong ito ng mga setting.py ay dapat magmukhang:

INSTALLED_APPS = [
    'feed',
]
Bago natin kalimutan, subukan natin na gumagana si Django. Gamit ang Command Python manager.py runserver 0.0.0.0:8000, maaari naming patakbuhin ang server at pagkatapos ay mag -navigate sa isang web browser sa computer na nagpapatakbo ng code sa http: // localhost: 8000 at makita ang isang halimbawa ng webpage (gumagana ito!) Tumigil sa server na may control c, katulad ng anumang iba pang utos. Ngayon, maghukay tayo sa pagsulat ng ilang code ng Python. Ang Django ay may tatlong pangunahing sangkap, lahat ng mga ito ay pinapatakbo ng code nang buo. Ang mga sangkap ay tinatawag na modelo, view at template, at ang bawat isa ay nasa mas mataas at mas mababang antas ayon sa pagkakabanggit bago maihatid ang webpage sa gumagamit. Ang modelo ay ang code na nag -iimbak ng impormasyon sa database para sa pagkuha, pag -uuri at pag -render. Nagpapasya ang view kung paano nai -render ang modelo, manipulahin, at binago, halos bawat view ay gagamit ng isang modelo nang direkta. Ang template ay ang HTML code na may ilang mga dagdag na kampanilya at mga whistles na tinatawag na template na wika. Ang template ay ibinibigay ng view kung saan napuno ito ng Python code atkonteksto tulad ng mga modelo at impormasyon (usuall string at integer) mula sa view. Ang Django ay may iba pang mga sangkap, kabilang ang ngunit hindi limitado sa: Mga setting, na nag -configure ng app tulad ng tinalakay namin. Ang mga URL, na mga pattern na sinusunod ng gumagamit upang makakuha ng pag -access sa mga tiyak na bahagi ng web application. Ang mga form, na tumutukoy kung paano ang impormasyon na ipinadala sa server ay hawakan at nai -render sa database pati na rin sa gumagamit. Ito ang pundasyon ng impormasyon sa pagproseso sa panig ng server, at maaaring tumanggap ng anumang uri ng impormasyon na mga tindahan ng computer, pinaka -kapansin -pansin na mga string ng teksto, numero, at totoo/maling mga booleans (karaniwang mga checkbox). Ang mga template, na kung saan ay HTML code at template ng wika at tulay ang agwat sa pagitan ng Python at HTML, na nangangahulugang ang impormasyon ng python ay maaaring ihain bilang HTML code na maaaring ma -access ng sinuman at maaaring ma -secure ang isang website na may paghihigpit na pag -access, habang ginagawang ma -access ang Python Code sa Web at kapaki -pakinabang Para sa iba't ibang mga layunin sa isang malayong aparato na hindieed na malapit sa server. Mga static na file, na karaniwang JavaScript at ito ay mga aklatan na nagsisilbi at naka -link sa template. Ang mga file ng media, na nagsisilbi o naka -host ang server, o nakasulat lamang sa server bago maproseso at nai -post sa isa pang server (isang bucket) para sa pag -host. Middleware, na kung saan ay mga piraso ng code na tumatakbo nang sabay -sabay sa bawat pagtingin at itinuturing na "kasama" sa view. Ang mga processors ng konteksto, na nagpoproseso ng konteksto ng bawat pagtingin at ginagamit upang magdagdag ng labis na konteksto. Ang mga pagsubok, na nagpapatunay na ang gumagamit o kahilingan ay pumasa sa ilang mga kinakailangan bago maibigay ang view. Ang mga mamimili, na nagdidikta kung paano hawakan at tumugon ang mga websocket sa komunikasyon. Admin, na ginagamit upang magrehistro ng mga modelo upang maaari silang manipulahin nang detalyado sa loob ng pahina ng admin ng Django, kung saan ang database ay maaaring ibigay sa pamamagitan ng isang graphic na interface. Kintsay, na tumutukoy sa mga asynchronous na gawain ng mga bahagi ng Django code ay maaaring magsimulaNning bago agad na magpatuloy sa susunod na gawain o linya ng code. Ang Django ay maaaring magkaroon ng maraming iba pang mga sangkap, na tatalakayin natin nang detalyado dito. Mayroong maraming mga paraan upang gawing mas functional ang Django, pagdaragdag ng mga websockets, na mabilis, naka -streamline na mga channel ng komunikasyon, kintsay, na nagsasagawa ng mga gawain ng asynchronous, at maraming mga piraso ng software para sa pagpapalawak ng django, lalo na sa mga function ng view, kung saan ang karamihan sa Ang code ay naisakatuparan. Ang mga function ng view ay susi dahil karaniwang ipinapahayag nila ang bawat piraso ng code na tiyak sa isang tiyak na pattern ng URL, o isang seksyon ng server. Una, galugarin natin ang mga function ng view. Ang mga function ng view ay nagsisimula sa mga pag -import na nagsasaad ng code na gagamitin sa view, at tinukoy gamit ang mga regular na kahulugan ng pag -andar o klase. Ang pinakasimpleng mga pananaw ay tinukoy ng kahulugan ng function def, at ibalik ang isang httpresponse na may isang pangunahing template. Magsimula tayo sa pamamagitan ng pagtukoy ng isang pangunahing pagtingin upang maibalik ang teksto na "Hello World". Tandaan na sa bawat oras na magdagdag kafter isang pahayag tulad ng DEF, kung, habang, para sa, atbp, kakailanganin mong magdagdag ng 4 na puwang para sa bawat isa sa mga naunang kahulugan na nais mong ilapat sa iyong pag -andar. Papasok tayo sa kung ano ang ibig sabihin ng bawat isa sa mga ito. Mula sa direktoryo ng aming site, i -edit ang file ng feed/views.py gamit ang nano at idagdag ang mga sumusunod na linya hanggang sa dulo ng

from django.http import HttpResponse

def hello(request):
    return HttpResponse('hello world')
Tumugon ang HttpResponse ni Django na may isang text string, na tinukoy sa pagbubukas at pagsasara '. Sa tuwing ipapasa mo ang impormasyon sa isang function o klase, tulad ng kahilingan o isang string, kakailanganin mong gumamit ng panaklong (, pagbubukas at pagsasara). Hindi na ito kailangan nating makita ang ating pananaw. Siyempre, hindi pa namin sinabi sa server kung saan eksakto ang view, kailangan pa rin nating tukuyin ang isang landas kung saan dapat i -render ang view. Magsimula tayo sa pamamagitan ng pagtukoy ng isang pangunahing landas sa app/urls.py, at papasok tayo sa mga pangkat ng landas mamaya. Sa app/urls.py, magdagdag ng isang linya pagkatapos ng mga pahayag sa pag -import pagkatapos ng simula ng pag -import ng view na nilikha lamang namin.

from feed import views as feed_views
Ngayon, tukuyin natin ang pattern ng view. Ang mga pattern ng view ay may tatlong sangkap, ang sangkap ng landas, na nagsasabi sa server kung saan umiiral ang view sa loob ng server (ang landas ng URL na ang mga uri ng gumagamit sa nabigasyon bar upang makapasok sa webpage), ang bahagi ng view kung saan tinukoy ang view, at a Friendly name para sa view kaya madaling makuha ang pattern kapag nagtatrabaho sa isang template, lalo na kaya ang pangalan ay maaaring mabago at mai -update kung kinakailangan upang gumawa ng puwang para sa isa pang view o kumuha ng mas lohikal na pangalan. Makatuwiran na gawin ang mga bagay sa ganitong paraan at maging kakayahang umangkop, dahil ang iyong codebase ay magiging isang palaging pagbabago ng kapaligiran na nangangailangan ng kakayahang umangkop at improvisasyon upang maging mahalaga at madaling makatrabaho. Narito kung ano ang magiging hitsura ng iyong view, maaari mong idagdag ito sa urlPatterns = [seksyon ng app/urls.py. Ang pattern ng view ay tinukoy sa tatlong mga sangkap na inilarawan sa itaas, at isang function na tinatawag na Landas. Ang iyong mga pattern ng URL ay isang listahan, kaya siguraduhing palaging tapusin ang bawat item sa kanilaSa isang kuwit, dahil ito ay naghihiwalay sa bawat isa. Ang bawat item ay dapat ding pumunta sa isang bagong linya, muli na may apat na puwang bago ito, tulad ng app sa mga setting.py. Tukuyin namin ang unang bahagi ng view na may isang walang laman na function ng string, upang lumikha ng isang view na tumatakbo sa direktoryo ng ugat ng web server. Ang iyong mga urls.py ay dapat na ngayon

from feed import views as feed_views

urlpatterns = [
    path('', feed_views.hello, name='hello'),
]
Ito ang batayan para sa paglikha ng isang website na may Django na ganap na static. Upang makagawa ng isang mas dynamic na website kung saan maaari nating simulan ang impormasyon sa caching, tulad ng mga imahe, video, audio at higit pa, kakailanganin nating gumamit ng mga modelo, na susuriin natin sa susunod. Sa ngayon, suriin natin ang aming code at patakbuhin ang server. Upang suriin ang code para sa mga error, tumakbo:

python manage.py check
Kung mayroong anumang mga error na mensahe, dapat mong maingat na suriin ang mga pagbabagong ginawa mo sa iyong app at tingnan kung mayroong anumang bagay na kailangang maayos, tulad ng isang extraneous o kulang sa espasyo, isang dagdag na character, isang unclosed string, anumang typo, anumang hindi sinasadya tinanggal na character, o kung ano pa man. Ang pagbabasa sa pamamagitan ng mensahe ng error (kung mayroon kang isa), dapat mong makita ang landas sa isang file na nilikha mo o na -edit kasama ang isang numero ng linya, kaya tingnan ang file at linya at tingnan kung maaari mong ayusin ang anumang bagay na naroroon . Kung naayos mo na ang isyu, patakbuhin muli ang utos sa itaas. Kapag handa na ang iyong software na tumakbo at gumagana, makikita mo ang output na "Suriin ng system na hindi natukoy ang mga isyu." Ngayon handa ka nang pumunta. Patakbuhin ang server na may:

python manage.py runserver 0.0.0.0:8000
Ngayon buksan ang isang web browser at mag -navigate sa http: // localhost: 8000. Dapat mong makita ang teksto na ibinalik sa panaklong at mga quote ng function ng HttpResponse sa iyong pagtingin. Ito ay isang pangunahing halimbawa lamang, ngunit kung ginawa mo ito sa ngayon, naiintindihan mo ang mga pangunahing kaalaman kung paano gumagana ang Linux, Bash, Python, at Django. Humukay tayo ng mas malalim sa ilang pagmomolde ng database, at galugarin ang kapangyarihan ng isang klase ng Python sa pag -iimbak ng impormasyon. Pagkatapos, magsisimula kaming makakuha ng isang mahigpit na pagkakahawak sa HTML at CSS bago namin gawin ang aming site na ganap na itinampok, nababaluktot at ligtas gamit ang JavaScript at pag -aaral ng makina. Ang mga klase ay naka -imbak sa mga modelo.py ng iyong app. Gamit ang nano, i -edit ang app/models.py at magdagdag ng isang bagong klase. Ang isang klase ay tinukoy sa kahulugan ng klase at ipinapasa ang isang superclass na minana mula sa, sa kasong ito models.model. Ang pangalan ng klase ay dumating pagkatapos ng kahulugan ng klase, at pagkatapos ng kahulugan ng klase A: (colon) ay ginagamit, bago ang mga katangian at mga kahulugan ng pag -andar na nakatali sa klase ay ipinapahiwatig sa ibaba. Ang aming klaseKailangan ng isang ID na maaari nating gamitin upang makuha ito at panatilihin itong natatangi, at nangangailangan din ito ng isang patlang ng teksto upang mag -imbak ng ilang impormasyon. Mamaya maaari kaming magdagdag ng isang timestamp, mga file, booleans (totoo o maling kahulugan na makakatulong sa aming code na gumawa ng mga pagpapasya tungkol sa kung ano ang gagawin sa modelo, at maaaring magamit upang pag -uri -uriin ito), isang pagkakataon upang itali ang modelo sa isang naka -log na gumagamit sa server, at marami pa. I -unpack natin ang code

from django.db import models # Ang import na ginagamit upang tukuyin ang aming klase at ito ay mga katangian

class Post(models.Model): # Ang kahulugan ng aming klase mismo
    id = models.AutoField(primary_key=True) # Ang ID ng aming modelo, isang awtomatikong nabuo na susi na hahayaan tayong mag -query sa modelo, panatilihin itong natatangi, at kapaki -pakinabang kapag kailangan nating makipag -ugnay sa modelo sa sandaling ito ay nilikha.
    text = models.TextField(default='') # Ang katangian ng aming mga tindahan ng klase, sa kasong ito, ilang teksto, na nag -default sa isang walang laman na string.
Isara at i -save ang file tulad ng ginawa namin dati upang matapos. Maraming iba pang mga patlang at mga pagpipilian na aming galugarin kapag ina -update namin ang klase na ito habang nagbabago ang aming app, ngunit ito ang pangunahing pangangailangan ng paglikha ng isang app upang mag -post ng ilang teksto. Gayunpaman, ang modelong ito ay hindi gagana nang mag -isa. Tulad ng inilarawan dati, kakailanganin namin ng isang pasadyang view at pasadyang pattern ng URL upang gawin ang modelong ito, at kakailanganin din namin ng isang form kasama ang isang template. Galugarin muna natin ang form. Upang tukuyin ang isang form, i -edit ang app/forms.py kasama si Nano at idagdag ang mga sumusunod na linya. Kakailanganin namin ang dalawang pag -import, ang aming klase ng form, pati na rin ang modelo na nilikha namin (feed.models.post), isang kahulugan ng klase na katulad ng modelo, at isang patlang kasama ang isang subclass na tinatawag na meta na tukuyin ang modelo na nakikipag -ugnay sa form na ang form ay nakikipag -ugnay kasama. Ang form ay maaari ring magkaroon ng isang function ng pagsisimula na nagtatakda nito batay sa impormasyon sa kahilingan, modelo o kung hindi man, galugarin natin ito sa ibang pagkakataon. Ang mga form ng modelo ay kapaki -pakinabang dahil maaari silang lumikha ng isang modelo o mag -edit din ng isang modelo,Kaya gagamitin namin ang mga ito para sa pareho. Tukuyin natin ang isa sa mga form.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',)
Ito ang mga pangunahing kaalaman sa kung ano ang hitsura ng isang form at modelo. Ang form na ito ng modelong ito ay maaaring magamit upang mag -instantiate o mag -edit ng isang post, binabago ang teksto na nilalaman nito. Titingnan namin ang pagsasama ng form na ito sa isang pagtingin sa susunod. Una, gawin natin ang paglipat at ilipat ang database upang ang aming code ay maaaring makipag -ugnay sa modelo kapag tumatakbo ito. Upang gawin ito, patakbuhin ang mga sumusunod na utos:

python manage.py makemigrations
python manage.py migrate
Aabutin ito ng isang minuto upang maisagawa, ngunit sa sandaling gawin nito, papayagan kang ma -access ang modelo sa mga tanawin, middleware, o kung saan man sa software. Magpatuloy tayo sa pamamagitan ng pagtingin sa kung saan makikita natin ang ating modelo. I -edit ang feed/views.py at idagdag ang sumusunod na code, tulad ng nabanggit. Hindi mo na kailangang magdagdag ng anuman pagkatapos ng # sign, ang code na iyon ay mga komento na ginagamit upang magpahiwatig ng impormasyon tungkol sa code. Magsisimula kami sa pamamagitan ng pag -import ng aming modelo sa mga view, at pagdaragdag nito sa isang konteksto kung saan maaari nating i -render ito sa isang template bilang isang listahan para sa pagpapakita. Susunod, magdagdag kami ng isang template kung saan maaari naming i -render ang form at ang modelo na may isang pindutan upang lumikha ng isang bagong bagay batay sa modelo at i -post ito sa server. Ito ay kumplikado, kaya gawin natin itong hakbang -hakbang. Bago natin tapusin ang view, lumikha tayo ng isang template na nagbibigay lamang ng modelo at tiyaking makikita natin ito sa pamamagitan ng paglikha ng isang bagong post sa shell. Narito kung paano dapat tumingin ang view na iyon:

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

def feed(request):
    posts = Post.objects.all() # Query ang lahat ng mga post sa database hanggang ngayon
    return render(request, 'feed/feed.html', {
        'posts': posts,
    })
Ang lahat ng ito ay mukhang medyo simple hanggang sa makarating kami sa ilalim. Render, ang halaga na ibinalik ng pag -andar sa halip na sa isang tugon ng HTTP tulad ng nakaraang halimbawa, palaging kumukuha ng isang kahilingan bilang unang input nito, tumatanggap ng isang konteksto (sa kasong ito ang mga post sa database), na maaari na ngayong ibibigay sa template , at ibabalik ang template na tinukoy sa pag -andar. Ang template ay magiging isang dokumento ng HTML na may kaunting isang wika na tinatawag na Jinja2, na nagbibigay ng impormasyon sa python sa HTML. Upang simulan ang paglikha ng mga template, gumawa ng dalawang direktoryo sa feed.

mkdir feed/templates
mkdir feed/templates/feed
Susunod, i -edit ang isang template sa direktoryo sa itaas, feed/template/feed, at idagdag ang code para sa halimbawang ito. Tingnan natin ang template para sa halimbawang ito.
 
<!doctype HTML>
<html>
<body>
<legend>Feed</legend>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
</body>
</html>
 
Ito ay isang napaka -simpleng template. Tinutukoy nito ang pagbubukas at pagsasara ng mga tag ng HTML, isang tag ng uri ng dokumento, isang tag ng katawan na may pamagat ng alamat, isang break tag na nagdaragdag ng isang maliit na linya sa buong screen, at isang para sa loop na nagbibigay ng bawat post sa listahan ng mga post bilang isang talata sa ang template. Ito lang ang kinakailangan upang mag -render ng mga post, ngunit wala pa sa database. Lumikha tayo ng ilan gamit ang shell. Maaari naming patakbuhin ang shell na may pamamahala.py

python manage.py shell
Ngayon, i -import natin ang aming modelo ng post

from feed.models import Post
Susunod, gagawa kami ng isang simpleng post na may isang string at lumabas sa shell. Ang string ay maaaring maging anumang bagay, hangga't ito ay wastong teksto.

Post.objects.create(text='hello world')
exit()
Panghuli, kakailanganin nating magdagdag ng isang pattern ng URL sa aming feed. Dahil ang aming feed app ay gagamit ng maraming mga URL at nais naming panatilihing maliit ang mga sukat ng file, lumikha tayo ng isang lokal na urls.py sa aming feed app na ganito:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.feed, name='feed'),
]
Kailangan din nating i -edit ang mga urls.py sa base app, anuman ang napagpasyahan naming tawagan ito, ito ang unang direktoryo na nilikha namin. I -edit ang app/app.py at idagdag ang sumusunod sa mga pattern ng URL

from django.urls import include # sa tuktok

urlpatterns = [
    # ... Nakaraang code dito
    path('feed/', include(('feed.urls'), namespace='feed')),
]
Ngayon, kapag pinapatakbo namin ang server na may python manager.py runserver, makikita namin ang pahina na nilikha namin dahil mayroon kaming modelo, view at template pati na rin ang pattern ng URL, kasama ang mga item sa database. Susunod, ipatupad natin ang form na nilikha natin at simulan ang paglikha ng aming sariling mga post. Ngunit bago tayo sumulat ng sobrang code, gumawa tayo ng isang backup gamit ang script na isinulat namin kanina, backup. Patakbuhin ang script na ito sa shell, maghintay ng ilang sandali, at ang lahat ng code ay mai -back up sa aming Git Repository.

backup
Ang pagpapatupad ng form ay medyo simple. I -import namin ang aming form, magdagdag ng isang handler ng kahilingan sa post, at i -save ang post sa database bago mag -redirect sa parehong view. Maaari naming gamitin ang pag -redirect function na na -import na namin, at isa pang function na tinatawag na baligtad upang makuha ang URL para sa pattern ng view. Susuriin namin ito gamit ang string na 'feed: feed' dahil ang namespace ng kasama na pattern ay feed, at ang view ay tinatawag ding feed.

from feed.forms import PostForm

def feed(request):
    posts = Post.objects.all() # Query ang lahat ng mga post sa database hanggang ngayon
    if request.method == 'POST': # Pangasiwaan ang kahilingan sa post
        form = PostForm(request.POST) # Lumikha ng isang halimbawa ng form at i -save ang data dito
        if form.is_valid(): # Patunayan ang form
            form.save() # I -save ang bagong bagay
        return redirect(reverse('feed:feed')) # Redirect sa parehong URL na may isang kahilingan sa pagkuha
    return render(request, 'feed/feed.html', {
        'form': PostForm(), # Siguraduhin na ipasa ang form sa konteksto upang ma -render natin ito.
        'posts': posts,
    })
Ngayon, kakailanganin naming i -update ang template upang account para sa bagong form. Magagawa natin ito sa pamamagitan ng paggamit ng
I -tag sa HTML at pag -render ng form sa template ng HTML na may isang pindutan ng isumite. Kakailanganin din namin ang isang token ng CSRF, isang token na pumipigil sa mga panlabas na site mula sa pag -post sa form nang hindi unang naglo -load ng isang pahina.
 
<!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>
 
Basagin natin ito. Mayroong isang bagong klase ng form, isang token, ang form mismo, at isang pindutan ng isumite. Medyo simple, ngunit kapag tinitingnan natin ito, baka gusto nating gawing mas mahusay. Gumagana ito, maaari kaming mag -post ng mga bagong post na may form at nai -save na sila ngayon sa database. Mayroong ilang mga bagay na nangyayari dito. Ginagamit namin ang mga tag ng HTML upang ipahayag na ang dokumento ay isang dokumento na HTML, gumagamit kami ng isang tag na template ({ % ... %}) upang maibigay ang token para sa form, at isa pa, {{...}} upang maibigay ang form. Mayroon din kaming isang loop upang i -render ang teksto gamit ang mga block tag at isang template tag. Mahalaga ang mga block tag dahil maaari naming tukuyin kung paano ang mga seksyon ng template ay nai -render sa kanila, at ang mga tag ng template ang batayan ng kung paano namin inilalagay ang mga variable sa aming code. Ngayon kailangan nating gawing mas mahusay ang aming app, dahil sa ngayon mukhang pangunahing pangunahing. Magagawa natin ito sa pamamagitan ng paggamit ng CSS, alinman sa inline, o sa mga klase na nakatali sa bawat bagay sa dokumento. Ang ganda talaga ng CSS dahil sinasabi nito ang lahat sa pahina kung paano ito dapat tumingin,At maaaring maging maganda ito. Mayroong ilang mga aklatan na maaaring gawin ito, ngunit ang aking personal na pagpunta ay bootstrap. Maaaring ma -download ang Bootstrap mula sa kanilang website,GetBootstrap.com/. Kapag doon, pindutin ang pindutan upang mabasa ang mga dokumento sa pag -install, at kopyahin ang code mula sa isama sa pamamagitan ng seksyon ng CDN. Kakailanganin mo ang code na ito sa tuktok ng iyong dokumento ng HTML, sa isang tag na tinatawag na ulo. Gayundin, magpatuloy tayo at lumikha ng isang template ng base upang hindi natin kailangang muling likhain ang mga link na ito sa bawat template. Gumawa ng isang bagong direktoryo na tinatawag na mga template na may mga template ng MKDIR, at pagkatapos ay i -edit ang mga template/base.html. Ito ay dapat magmukhang ganito:
 
<!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>
 
Siguraduhin na kopyahin ang CSS at JavaScript, ang .css at .js file, dahil kakailanganin namin ang JavaScript upang gawing mas gumagana ang aming site sa hinaharap. Ngayon, bumalik tayo sa bash shell at magpatakbo ng isang mabilis na utos. Tandaan, kung kailangan mong ma -access ang virtual na kapaligiran, i -type ang mapagkukunan VENV/BIN/I -aktibo. Papayagan ka nitong mag -install ng mga pakete ng Python nang lokal sa isang paraan na pinapayagan ang mga ito na ma -access ang Django. Upang mabigyan ang aming mga form na nabuo ng mga klase ng Django Bootstrap, gagamitin namin ang isang Python package na tinatawag na Crispy Forms. Maaari naming i -download ito sa sumusunod na utos

pip install django-crispy-forms
Kapag na -install ito, idagdag ito sa mga setting.py

INSTALLED_APPS = [
    # ... Nakaraang code dito
    'crispy_forms',
]
Ngayon, bumalik sa aming template ng feed, maaari nating alisin ang ilang mga bagay. Alisin natin ang simula at pagtatapos ng dokumento at palitan ito ng mana mula sa aming template ng base, gamit ang pagpapalawak at kahulugan ng bloke. Gayundin, magdagdag kami ng isang import ng filter ng template na may pag -load at isang filter ng template sa form. Panghuli, magdagdag tayo ng isang klase ng bootstrap sa pindutan sa form upang gawin itong mas katulad ng isang pindutan. Iyon ay dapat magmukhang ganito:
 
{% 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 %}
 
Maganda! Iyon ay medyo medyo code na. Susunod, dapat nating subukan ito at tiyakin na makikita natin na ang lahat ay mukhang maganda, at siguraduhin din na ang lahat ay gumagana nang maayos. Patakbuhin ang server tulad ng bawat nakaraang mga tagubilin at siguraduhin na ang hitsura ng site at gumagana nang maayos. Mahusay na trabaho! Handa ka nang lumipat sa susunod na hakbang, kung saan magdagdag kami ng pag -andar ng pag -login ng gumagamit gamit ang mga katulad na URL, form, view at template. Mahalaga ang batayang template, at magpapatuloy kaming baguhin ito at gagawa ng mga pagbabago kung kinakailangan, ngunit sa ngayon ay ituon natin ang pagtuon sa paggawa ng aming site na mas ligtas, sa pamamagitan ng pagpapagana ng mga gumagamit na mag -log in gamit ang isang username at passcode, at sa huli kahit na mas mahalagang impormasyon na Makakatulong na panatilihing ligtas ang iyong app at ang iyong sariling account ay maa -access lamang sa iyo. Upang gawin ito, kakailanganin nating gamitin ang modelo ng gumagamit na binuo sa Django. Ang modelo ng gumagamit ay isang modelo ng database, tulad ng aming post, na maaaring mai -log upang mag -log ng isang gumagamit sa website. Sa hinaharap, bago namin i -deploy ang site sa internet, gagawin naminPalawakin ang modelong ito sa iba pang mga modelo na maiugnay dito, at bumuo ng mga karagdagang hakbang sa seguridad para sa pag -login na lumalaban sa phishing. Magsisimula kami sa pamamagitan ng paggamit ng ilang built in na mga form sa pag -login na ibinibigay ni Django. Una, lumikha tayo ng isang bagong app na gagamitin namin upang maibigay ang mga template at view para sa pangunahing pahina ng pag -login. Gumagawa din kami ng iba pang mga app upang kumatawan sa patuloy na mga hamon sa pag -login upang ma -secure ang app, kabilang ang isang pincode, pagkilala sa facial, malapit sa komunikasyon sa larangan, panlabas na aparato, pagpapatunay ng multi factor, at pagkilala sa fingerprint. Napag -usapan na namin ang pagsisimula ng isang app. Mula sa aming direktoryo, sa loob ng virtual na kapaligiran, pumasa sa pamamahala.py mga ito

python manage.py startapp users
Ngayon, dapat tayong magkaroon ng isang direktoryo para sa bagong app. Magsimula tayo sa pamamagitan ng paglikha ng isang view sa direktoryo na tumutugma sa pag -login ng gumagamit. Ang Django ay nagtayo ng mga view para sa mga logins ng gumagamit, ngunit ang mga ito ay hindi angkop para sa amin dahil kailangan namin ng isang pasadyang pagtingin, na mas mabuti na gawin sa isang kahulugan. Sa view na ito, magsisimula kami sa pamamagitan ng pagsuri para sa isang kahilingan sa post, pumasa sa kahilingan.post sa isang pag -login na na -import mula sa Django, patunayan ang account ng gumagamit, at mag -log in sa gumagamit bago i -redirect ang mga ito sa aming feed app. Sa mga gumagamit/view.py, idagdag ang sumusunod na code

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'] # Kunin ang username at password mula sa kahilingan sa post
        password = request.POST['password'] # Patunayan ang gumagamit
        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()})
Ito ang kailangan mo para sa isang pangunahing view ng pag -login. Ngayon, lumikha tayo ng isang form para sa view sa pamamagitan ng pagpapalawak ng template ng base. Magsisimula kami sa pamamagitan ng paglikha ng isang bagong direktoryo para sa mga template sa folder ng mga gumagamit.

mkdir users/templates
mkdir users/templates/users
Ngayon, dapat nating mai -edit ang mga gumagamit/template/gumagamit/login.html. Habang naroroon kami, gagawa kami ng isang template upang payagan ang gumagamit na mag -sign up din.

nano users/templates/users/login.html
Ngayon, sa template,
 
{% 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 %}
 
Ito ang mga pangunahing kaalaman ng isang template ng pag -login. Ito ay talagang katulad ng iba pang template sa istraktura, ngunit mukhang medyo naiiba ito kapag na -render ito. Maaari naming kopyahin ang code na ito upang makabuo ng isa pang katulad na template na tinatawag na Register.html, kung saan babaguhin natin ang mga salita at gumamit ng isang bagong form na itinatayo namin. Gawin muna natin ang template. I -edit ang mga gumagamit/template/gumagamit/rehistro.html at idagdag ang sumusunod na code:
 
{% 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 %}
 
Ngayon, bumuo tayo ng isang form para sa aming pagpaparehistro ng gumagamit at bilog pabalik sa mga tanawin bago namin i -upgrade ang aming mga logins ng gumagamit na may isang modelo. Gagawin namin ang form na ito na pangunahing upang magsimula, ngunit isama ang higit pang mga detalye at mga tampok ng seguridad tulad ng mga kasunduan at CAPTCHA sa hinaharap. I -edit ang mga form na may mga gumagamit/form ng nano.py, at idagdag ang sumusunod na code.

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']
Kaya mayroon kaming isa pang form dito, na gumagana nang simple. Ito ay isang form ng rehistro ng gumagamit na may isang username, email at password, pati na rin ang isang kumpirmadong patlang ng password. Tandaan na ang form na ito ay hindi nagpapalawak ng mga regular na form ng form.Form, ito ay isang form ng modelo na nangangahulugang mayroon itong meta. Ang isang patlang ay tinukoy lamang pareho, at ang meta ng klase ay tumutukoy sa modelo ng form ay tumutugma sa natitirang impormasyon na isusulat sa form. Karamihan sa mga ito ay mayroon na sa Django na binuo sa UserCreationForm, kaya gagamitin namin iyon bilang batayan para sa klase (naipasa sa panaklong). Susunod, susuriin namin ang view upang magrehistro ng isang gumagamit, ngayon na mayroon kaming isang form at isang template. Ito ay isang modelform, tulad ng isa sa bagong view ng post. I -edit ang mga gumagamit/view.py at idagdag ang sumusunod na code:

# ... halaga
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})
Ito ang kailangan namin upang makakuha ng isang nakarehistro ng isang gumagamit, ngunit dapat tayong magkaroon ng karagdagang impormasyon. Nais naming malaman ang oras na nakarehistro ang gumagamit, kung anong oras sila ay huling sa site, ilang impormasyon tungkol sa kanila, tulad ng isang talambuhay, timezone, atbp Gayundin, kakailanganin nating i -update ang aming modelo ng feed, mag -post, upang account para sa gumagamit Model at katangian ng mga post sa bawat gumagamit. Upang magawa iyon, i -update namin ang mga modelo.py sa parehong mga app. Magsimula tayo sa pamamagitan ng pag -edit ng modelo ng feed. Ito ay dapat magmukhang ganito ngayon:

from django.db import models # ... halaga
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') # Idagdag sa linyang ito
    text = models.TextField(default='')
Bigyang -pansin ang pangalawang linya na naidagdag sa file. Ito ay isang dayuhang susi, na kung saan ay maiugnay ang bawat post sa isang solong gumagamit bawat post, upang matiyak nating i-save namin ang mga post sa isang batayan ng gumagamit-per-user at walang post na maaaring gawin nang hindi naiugnay ito sa isang gumagamit. Tinukoy namin ang dayuhang susi na ito sa klase na kinakatawan nito, isang tanggalin na argumento upang matiyak na ang mga post ay tinanggal sa Nilikha, at isang kaugnay na pangalan, na magagamit namin upang sumangguni sa mga bagay na post na nilikha ng gumagamit. Ang kaugnay na pangalan na ito, hindi katulad ng post.author, ang may -akda ng The Post, ay nagbibigay sa amin ng gumagamit na nag -post ng post mismo. Maaari na nating makuha ang mga post na ginawa ng isang gumagamit sa pamamagitan ng pagpapatakbo ng user.posts.all (), o may -akda.posts.all (). Ngayon, gawing mas nababanat ang aming mga logins. Maaari na nating gawin ang aming site na hindi gaanong mahina sa phishing sa pamamagitan lamang ng rate na nililimitahan ang bilang ng mga beses na papayagan namin ang isang pag -login saSite, madali ito. Magsimula din tayong mag -imbak ng ilang impormasyon tungkol sa bawat gumagamit bago habang patuloy nating nabuo ang aming app. Pag -edit ng mga gumagamit/modelo.py, idagdag ang sumusunod

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='')
Tandaan na ang modelong ito ay medyo katulad sa modelo ng post. Mayroon kaming isang karagdagang pag -import, Timezone, na magbibigay -daan sa amin upang magtakda ng mga default sa mga patlang ng DateTime, at mayroon din kaming isang characterfeild at textfield tulad ng post. Ang paggamit ng lahat ng mga timestamp na ito ay tumutulong sa amin na ma -secure ang site at maunawaan ang paggamit nito, at ang mga patlang ng teksto ay hayaan nating magbigay ng impormasyon tungkol sa bawat gumagamit, o may -akda, sa website. Ang OnetoOnefield ay dapat na ang tanging menor de edad na pagsasaalang -alang, kumikilos ito nang eksakto katulad ng isang foreginkey ngunit may isa lamang sa bawat kasunod na modelo. Sa ganitong paraan, ang gumagamit ay mayroon lamang isang profile, habang maaaring mayroon silang maraming mga post. Ngayon, pagbutihin natin ang aming pag -login at magrehistro ng mga view upang account para sa profile. Una, i -edit ang mga gumagamit/view.py at tumuon sa view ng rehistro:

# ... halaga
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) # Siguraduhing idagdag ang linya na ito, upang lumikha ng isang profile para sa gumagamit
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
Lumilikha lamang ito ng isang profile para sa gumagamit, nang hindi pinupuno ang alinman sa impormasyon. Ngayon, nais naming tiyakin na ang account ng gumagamit ay hindi maaaring mai -log in nang madalas, o hindi bababa sa mga password ay hindi maaaring masubukan nang madalas, kaya't i -update natin ang view ng pag -login.

# … Mga pag -import
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(): # Tandaan na susuriin natin ngayon kung maaaring mag -log in ang gumagamit
            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: # Kung ang pag -login ay hindi matagumpay,
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # Ito ang bahagi kung saan ina -update namin ang profile ng mga gumagamit
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # Kaya hindi na sila maaaring mag -log in muli ng ilang segundo
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Ito ang pangunahing pangunahing pangunahing seguridad. Siguraduhin na ang site ay hindi mahina laban sa isang tao na sinusubukan lamang ang bawat posibleng kumbinasyon ng password, o kahit na ilan sa mga ito nang sabay. Hindi ito magiging pagkabigo sa ordinaryong gumagamit na nakakaalam ng kanilang passcode at nag -log in lamang sa ilang mga aparato, ngunit mapapanatili nito ang maraming mga phishing robot sa labas ng app. Tandaan na nagdagdag kami ng isang pahayag na may isang variable, can_login, dapat itong maging isang oras sa nakaraan, at i -update ito sa bawat hindi matagumpay na pag -login gamit ang parehong username. Sa ganitong paraan, ang isang nakakahamak na gumagamit ay hindi makakapaghula ng isang password kahit saan malapit nang mabilis. Ang bilang ng mga segundo sa DateTime.TimeDelta () ay maaaring ma -update din, at ang website ay magiging mas nababanat ngunit bahagyang hindi gaanong magagamit sa higit pang mga segundo. Inirerekumenda ko ang 15 upang magsimula sa. Tandaan, nagtayo kami ng isang backup na script upang mai -save ang aming trabaho, kaya't ituloy natin at i -back up kung ano ang mayroon tayo hanggang sa tiyakin na na -save natin ang lahat. Patakbuhin ang utos:

sudo backup
Muli, mai -save nito ang iyong trabaho sa ngayon. Inirerekumenda ko ang pagtakbo ng madalas na mga backup upang mai -save ang iyong trabaho, at baka gusto mo ring patakbuhin ang isang backup na trabaho. Maaari mong gawin ito gamit ang isang utility ng UNIX na tinatawag na Cron. Upang maisaaktibo ang utility na ito, patakbuhin ang sumusunod na utos at ipasok ang iyong password:

sudo crontab -e
Kung hindi mo pa napili ang Opsyon 1 para sa Nano, ang text editor ay dapat na pamilyar ka, at mag -scroll sa ilalim ng file gamit ang mga arrow key. Idagdag ang sumusunod na linya:

0 * * * * sudo backup
Ginagamit ng Cron ang format na minuto, oras, araw ng buwan, buwan, araw ng linggo, kung saan ang isang * o isang numero ay kumakatawan kung kailan tatakbo ang utos. Gamit ang isang 0 para sa minuto at * para sa natitirang mga pagpipilian, maaari kaming magpatakbo ng isang utos sa unang minuto ng bawat oras sa pagsisimula ng minuto. Ito ay nagbibigay -daan sa amin na i -back up ang code nang awtomatiko. Ang lahat ng mga trabaho ni Cron kapag pinatay na may sudo run bilang ugat, kaya hindi namin kailangang mag -type sa isang password bawat oras. Upang mas madaling i -back up ang aming code nang hindi gumagamit ng isang password, huwag paganahin ang password para sa aming backup na utos. Gagawin natin ito sa pamamagitan ng pagpapatupad ng sumusunod na utos at pagpasok ng isang password:

sudo visudo
Ngayon, mag -scroll tayo sa ilalim ng file at magdagdag ng isa pang linya:

ALL ALL=NOPASSWD: /bin/backup
Pinapayagan kaming patakbuhin ang utos na "backup" bilang anumang gumagamit, nang walang password. Ang format para dito ay madali, prefix lamang ang linya na may "lahat ng lahat = nopasswd:/bin/" at magtatapos sa utos, halimbawa/bin/backup, na umiiral sa/usr/bin/. Ngayon, simulan nating magtrabaho sa email. Mahalaga ang email para sa mga website, dahil ito ay isang paraan upang mapanatili ang isang website na mas ligtas, i -verify ang mga gumagamit ay mga tunay na tao, at maging ang mga produkto o serbisyo sa merkado sa mga customer. Maraming mga tao na madalas na suriin ang Internet sa kanilang email araw -araw, at tumatanggap ng lahat ng mga uri ng email sa marketing tungkol sa Alinmang pinakamahusay na gumagana para sa iyo. Una, maaari kang magbayad para sa isang serbisyo sa email na magbibigay -daan sa iyo upang magpadala ng email mula sa iyong domain at nangangailangan ng kaunting code. Maraming mga serbisyo na nag -aalok nito, tulad ng Google Workspace, SendInblue, MailGun, at marami pa. Kung hindi man, maayos ka sa pagbuoAng iyong sariling serbisyo sa email sa loob ng iyong server mula sa simula. Inirerekumenda ko ang pagpipiliang ito, kahit na mas maraming code at maaaring mangailangan ng espesyal na pagho -host. Hindi mo magagawang magsimula ng isang mail server mula sa iyong computer sa bahay na malamang, kaya sige na at suriin ang pagsasaayos at code upang magpadala ng email bago kami magsimula ng isang server sa ulap at lumikha ng aming sariling mail server sa loob. Una, i -edit ang mga setting.py sa mga sumusunod

nano app/settings.py
Kung saan ang app ay ang pangalan ng app na nilikha mo gamit ang StartApp. Idagdag ang mga sumusunod na linya:

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)
Siguraduhing baguhin ang mga ito kapag handa ka nang i -deploy ang iyong app, susuriin namin ito sa ibang pagkakataon. Ang setting ng email_address ay dapat na email na nais mong ipadala mula sa, at ang password (email_host_password) ay dapat na itakda sa password na iyong nabuo para sa server. Nai -load ko ang password mula sa isang config file upang maiwasan ito sa code gamit ang sumusunod na lohika, sa itaas ng mga linyang ito sa mga setting.py:

import os
import json
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
Pagkatapos, nag -set up ako ng isang JSON file na may config in /etc/config.json gamit ang nano tulad ng sumusunod. Upang mai -edit ang file:

sudo nano /etc/config.json
Idagdag ang mga sumusunod na linya:

{
	“EMAIL_HOST_PASSWORD”: “<some password here>”
}
Patuloy naming i -edit ang config file at idagdag ang lahat ng mga password at mga susi na gagamitin namin sa app. Sa ngayon, mabilis nating suriin kung paano magpadala ng email gamit ang Python. Una, lumikha tayo ng isang template para sa isang email sa pag -verify na maaari naming ipadala sa aming mga gumagamit, at ilagay ito sa direktoryo ng mga template ng gumagamit. Ang template na ito ay isusulat sa 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>
 
Ang email na ito ay medyo simple. Ito ay tumatagal ng isang konteksto ng isang gumagamit, ang base URL para sa site, at isang ID ng gumagamit at token na ginagamit upang mapatunayan ang email ng gumagamit. Siguraduhin na tukuyin ang base URL sa mga setting.py bago namin isulat ang ilang code ng Python upang maibigay ang template. Sige at idagdag ang mga sumusunod na linya sa app/setting.py, malapit sa simula.

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

BASE_URL = PROTOCOL + '://' + DOMAIN
Sa kalaunan, kapag handa na ang iyong site para sa internet at inilalagay mo ito, nais mong tukuyin ang iyong domain bilang pangalan ng domain na binili mo upang kumatawan sa site. Ito ang pangalan na mai -type mo sa Navbar upang ma -access ang iyong site. Sa ngayon, maaari mong iwanan ang blangko ng domain o gumamit ng isang placeholder. Gusto mo ring baguhin ang site_name sa isang pangalan na nais mong ibigay sa iyong site, ng iyong pagpili. Bago tayo magpadala ng email, lumikha tayo ng isang token generator upang magkaroon tayo ng isang token ng pag -activate ng account na hindi kailanman mag -expire. Magagawa natin ito sa pamamagitan ng pagbuo at pag -import ng isang token ng pag -activate ng account na mukhang sumusunod. I -edit ang file:

nano users/tokens.py
Idagdag ang sumusunod na code:

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()
Ang pangunahing generator ng token na ito ay bumubuo ng isang token maaari naming ipadala ang gumagamit sa isang URL at maaaring magamit ng gumagamit upang mapatunayan ang kanilang email at maisaaktibo ang kanilang account. Susunod, tingnan natin kung paano magpadala ng isang email. Gamit ang nano, i -edit ang mga gumagamit/email.py.

nano users/email.py
Ang pagpapadala ng email sa pag -verify ng HTML ay magiging ganito:

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)
Ito ay medyo simple. Nag -import kami ng mga pag -andar na kailangan naming ipadala ang email, i -render ang email gamit ang mga template, at ang aming mga setting, at pagkatapos ay tukuyin namin ang email sa pamamagitan ng pangalan ng template at ipadala ito sa gumagamit gamit ang isang function. Mapapansin mo na hindi namin tinukoy ang pagpapaandar upang maipadala ang mail, send_html_email, gayon pa man, isulat natin ito sa ibaba ng code na naidagdag na namin sa mga gumagamit/email.py

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()
Ito ay medyo mas kumplikado, at hindi pa kami handa na patakbuhin ang lahat ng code na ito. Pansinin na tinukoy namin ang isang unsub_link, ang link na magagamit ng gumagamit upang mag -unsubscribe mula sa aming mga email. Mahalaga ito, dahil ang mga gumagamit ay kailangang mag -opt out sa aming mga email maliban kung nais nilang makita ang mga ito, anumang oras. Nagdaragdag din kami ng isang alternatibong teksto sa aming mensahe, na kung saan ay ang mensahe ng HTML na nakuha ng mga tag ng HTML. Panghuli, susuriin namin kung ipinadala ang email, at kung hindi ito, minarkahan namin sa profile ng gumagamit na ang kanilang email ay hindi wasto. Bumalik tayo sa mga modelo ng gumagamit upang maisagawa natin ang lahat ng ito. Kailangan naming tukuyin ang isang function upang makabuo ng isang link upang mag -unsubscribe, at tukuyin ang isang patlang ng Boolean upang markahan na ang email ng gumagamit ay hindi wasto. Una, idagdag ang mga sumusunod na pag -import sa tuktok ng mga gumagamit/modelo.py

nano users/models.py

# …
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from django.urls import reverse
Susunod, magdagdag tayo ng mga pag -andar sa modelo ng gumagamit upang gawin ang token at suriin ang token na ginamit upang maisaaktibo ang email, pati na rin ang patlang upang mai -save kung matagumpay na natatanggap ng gumagamit ang kanilang mail. Sa mga gumagamit/modelo.py muli, idagdag ang sumusunod na code sa dulo ng modelo (indented code)

# …
    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) # May bisa sa loob ng 30 araw
        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,})
Ito ay medyo simple, gumagamit kami ng isang timestampsigner, na kung saan ay isang pangunahing tool sa kriptograpiya, upang lumikha ng isang token na mag -expire pagkatapos ng isang tiyak na oras, at gumagamit din kami ng isa pang pag -andar upang suriin kung ito ay may bisa. Ginagamit namin ang mga token na ito nang dalawang beses, isang beses upang mapatunayan ang email, at isang beses para sa isang unsubscribe link. Ngayon na mayroon tayo nito, ang huli sa gawaing kakailanganin nating gawin ay nasa mga pananaw. Sa loob ng mga gumagamit/view.py, magdagdag tayo ng mga view upang mapatunayan ang email address, at upang mag -unsubscribe.

nano users/views.py
Una, idagdag ang mga sumusunod na pag -import. Itinapon ko ang ilang dagdag kaya hindi na namin kailangang mag -import muli ng mga item sa ibang pagkakataon.

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 # Siguraduhin na i -import ang pag -andar ng pagpapadala ng email sa pag -verify
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
Maaari ka nang magkaroon ng ilan sa mga pag -import na ito, ngunit hindi ito nasasaktan na ulitin ang mga ito. Kakailanganin mong i -import ang pag -andar ng pagpapadala ng email sa pag -verify, pati na rin ang account_activation_token mula sa mga gumagamit.tokens, bukod sa iba pang mga import. Ngayon, sa ilalim ng file, idagdag ang sumusunod na code:

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)):
        # i -unsubscribe ang mga ito
        profile = user.profile
        profile.subscribed = False
        profile.save()
        return render(request, 'users/unsubscribe.html')
    # Kung hindi man ay nag -redirect sa pahina ng pag -login
    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 (kahilingan, gumagamit)
        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})
Ito ay maraming code. Basagin natin ito. Ang unang pag -andar, malinis at simple, unsubscribe ang gumagamit mula sa mailing list. Ang pangalawang pag -andar ay nagpapa -aktibo sa kanilang email, at mapapansin mo na nagdagdag ako ng isang puna na nagkomento, SendWelComeEmail. Inaanyayahan kang gumamit ng isang template ng email at kahulugan ng pag -andar upang magpadala ng isang malugod na email, wala pa ako. Ang huling pag -andar na itinapon ko ay mahalaga, dahil mag -expire ang mga email sa pag -activate. Samakatuwid, kakailanganin nating ibenta ang email ng pag -activate ng ilang oras. Maaari kaming gumamit ng isang pangunahing form para dito, at tawagan ang function upang maipadala ang email sa pag -verify. Bago natin ito gawin, tiyakin na maipapadala ito sa una, sa pamamagitan ng pagdaragdag ng isang function na tawag sa view ng rehistro. Idagdag ang linya na ito bago ang pag -redirect sa view ng rehistro, def rehistro, sa mga gumagamit/view.py.

nano users/views.py

# ... (pagkatapos) def rehistro (kahilingan):
            send_verification_email(user)
# ... (bago) i -redirect (
Hindi mo na kailangang idagdag ang una at huling mga linya sa snippet ng code na iyon, tiyaking ipinapadala ng view ng rehistro ang email ng pag -verify sa gumagamit. Ito ay dapat magmukhang ganito:

# … Mga pag -import
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) # Siguraduhin na idagdag ang linya na ito!
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
Ngayon, kakailanganin naming magdagdag ng isang form upang maibenta ang email ng pag -activate. Sa mga gumagamit/forms.py, idagdag ang sumusunod na form:

# ... (Halaga)
class ResendActivationEmailForm(forms.Form):
    email = forms.EmailField(required=True)
Kakailanganin din namin ang isang template na naaayon sa form na ito ng muling pag -activate ng email. Idagdag natin ang template na ito. I -edit ang file:

nano users/templates/users/resend_activation.html
Susunod, idagdag ang sumusunod na code sa file.

{% 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 %}
Whew, marami yan! Ngayon, kapag inilalagay namin ang code sa aming server, magagawa naming magpadala ng email sa HTML at buhayin ang mga account ng gumagamit na may isang pag -click sa email. Maaari rin naming magpadala ng isang simpleng pag -welcome email, kaya tingnan natin kung paano gawin iyon. Bumalik sa mga gumagamit/email.py, idagdag ang sumusunod na code:

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)
Gayundin, kakailanganin namin ng isang template upang maibigay ang lahat ng impormasyong ito. Sa aking website, ang template ay mukhang sa ibaba, ngunit malugod mong mai -format ito gayunpaman gusto mo.
 
<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>
 
Tandaan na wala kaming pagsasara ng katawan o mga tag ng HTML, dahil idinagdag namin ang mga ito kapag idinagdag namin ang link ng HTML Unsubscribe. Mahalaga ito, ngunit hindi namin nais na tukuyin ang mga ito nang dalawang beses. Kaya ano ang susunod? Malayo na tayong dumating. Talagang, dapat nating maging handa na i -deploy ang site sa isang server. Maaari naming idagdag ang @login_required na dekorador at gawing ligtas ang aming mga pananaw, kumuha ng mga pag -signup ng gumagamit, magpadala ng sumusunod na email, at impormasyon sa cache, na siyang batayan ng kung ano ang kailangang gawin ng isang website upang manatiling may kaugnayan. Magdaragdag kami ng ilang mas kapaki -pakinabang na mga tampok, at pagkatapos ay bumuo ng isang batayan para sa pag -deploy ng aming code sa isang remote server, pag -set up ng isang mail server, pagsasaayos ng domain, at mga filter upang gawing ligtas at naaangkop ang aming site. Kakailanganin din namin ng isang view ng pag -reset ng password, kaya't idagdag natin iyon nang mabilis. Ang Built sa Django na Built In Password Reset View ay nasira sa ilang mga pag -andar, ngunit titingnan namin kung paano isulat ang aming sariling view, template ng email, mga form, at mga pattern ng URL. Narito kung ano ang hitsura ng view, sa mga gumagamit/view.py

# ... halaga
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)
Ang form na ito ay itinayo sa django, ngunit kakailanganin namin ng isang template upang kumpirmahin ang pag -reset ng password, mga gumagamit/template/gumagamit/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 %}
 
Mayroon din kaming isang template upang magpadala ng isang email na i -reset ang password, na may isang simpleng form, sa mga gumagamit/template/gumagamit/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 %}
 
Ang template para sa email mismo ay simple, ito ay isang pangunahing HTML file na nag -render ng isang link upang i -reset ang password, sa mga gumagamit/template/gumagamit/password_reset_email.html. Awtomatikong isasalin ni Django ang file na ito.
 
<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>
 
Kakailanganin din namin ng dalawa pang mga template. Ang una ay upang kumpirmahin na ang email ay ipinadala. Ang mga pananaw para sa mga ito ay nasa Django, kaya kailangan lang nating tugunan ang mga ito sa mga urls.py. Ang template na ito ay matatagpuan sa mga gumagamit/template/gumagamit/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 %}
 
At sa wakas, upang kumpirmahin na kumpleto ang pag -reset ng password, mga gumagamit/template/gumagamit/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 %}
 
Ngayon, kailangan namin ng mga pattern ng URL para sa mga pananaw na ito. Sa mga gumagamit/urls.py, idagdag ang mga sumusunod na pattern ng URL:

urlpatterns = [
    # ... Nakaraang mga URL dito
    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'),
]
Apat na mga template, marami iyon! Ngunit ngayon maaari nating siguraduhin na mai -reset ang password ng gumagamit anumang oras na kailangan natin, lahat mula sa web browser. Naiintindihan ko na ito ay maraming code. Kung tila medyo sa iyong ulo, ok lang iyon. Mapapabuti mo, mapapabuti ang iyong pag -unawa, at magiging mas karampatang ka sa code sa lalong madaling panahon. Kung ikaw ay lubos na nawala, inirerekumenda kong bumalik sa software na ito sa ibang pagkakataon pagkatapos magtrabaho sa isang self-paced na matutong mag-code ng kurso sa online. Ang mga ito ay karaniwang libre upang makapagsimula, at gagabayan ka sa lahat ng kailangan mong maging matagumpay kapag bumalik ka sa proyektong ito. Kung sa tingin mo ay handa ka nang magpatuloy, basahin, sa susunod, masakop namin ang pag -deploy ng iyong code sa isang remote server at pag -set up ng isang mail server, pati na rin ang pag -automate ng iyong pag -deploy gamit ang bash upang maaari kang palaging mag -set up ng isang bagong proyekto kasama Ilang simpleng mga utos. Ang huling bagay na kailangan nating gawin bago mag -deploy sa isang remote server ay gawing mas ligtas ang aming site. IkawPansinin na ang view ng pag -login ay tumatagal lamang ng isang username at password, at walang multi factor na pagpapatunay o isang time code. Ito ay isang madaling pag -aayos, at sa parehong code, maaari naming gawin ang aming site na magpadala ng mga text message at maging tumutugon sa mga text message na ipinadala sa server. Upang magsimula, babalik kami sa mga modelo ng gumagamit at magdagdag ng isang timestamp signer na kumakatawan sa bawat pag -login. Magdaragdag din kami ng isang natatanging, umiikot na identifier sa modelo ng gumagamit na gagamitin upang magdagdag ng labis na seguridad sa aming pag -login. Pag -edit ng mga modelo ng gumagamit, mga gumagamit/modelo.py, idagdag ang sumusunod

from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
# Siguraduhin na i -import ang UUID, TIMESTAMP Signer at URL Generator (baligtad)
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='')
    # Idagdag ang code na ito dito
    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)

    # At idagdag ang pagpapaandar na ito
    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) # Wasto para sa 3 mins
        except (BadSignature, SignatureExpired):
            return False
        return True
Siguraduhin na ang iyong mga gumagamit/modelo.py ay mukhang ganito, bukod sa mga komento (code sa mga linya na may #). Babasagin ito, simple ito. Mayroon kaming ilang mga pag -import, isang timestampsigner na kung saan ay isang cryptographic utility na maaaring makabuo ng isang ligtas na code at mapatunayan ito upang matiyak na ito ay may bisa, ginamit lamang nang isang beses, at hindi mas matanda kaysa sa isang tiyak na bilang ng mga segundo. Gumagamit din kami ng isang UUID, na kung saan ay isang natatanging identifier na nagpapakilala sa aming gumagamit sa pag -sign ng token, at sa URL kung saan ipinadala ang token sa gumagamit. Gagamitin namin ang pangunahing cryptography na ito upang makabuo ng isang dalawang kadahilanan ng view ng pagpapatunay. Bago tayo gumawa ng iba pa, patakbuhin natin ang paglilipat upang ma -update ang aming mga modelo ng gumagamit. Sa direktoryo na may namamahala.py, patakbuhin ang mga sumusunod na utos upang gawin at kumpletuhin ang paglipat.

source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
Mahalaga ito dahil sa tuwing gumawa tayo ng mga pagbabago sa mga modelo, kakailanganin nating lumikha ng mga talahanayan at i -update ang database na may mga default bago maaari nating gamitin ang mga modelo. Susunod, i -improvise natin ang aming view ng pag -login upang mai -redirect sa isang pangalawang view ng pagpapatunay. Sa mga gumagamit/view.py, alisin ang pag -andar ng pag -login at mag -redirect sa URL na nabuo lamang namin sa mga modelo ng gumagamit.

# ... halaga

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(): # Tandaan na susuriin natin ngayon kung maaaring mag -log in ang gumagamit
            # Alisin ang function ng auth_login na narito
            messages.success(request, 'Your password was accepted. Please continue.')
            if user.profile.mfa_enabled:
                return redirect(user.profile.create_auth_url()) # Tandaan na nag -redirect kami sa isang bagong URL dito
            else: # Kung ang gumagamit ay hindi gumagamit ng pagpapatunay ng multi-factor, mag-log in lamang ito.
                auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
                return redirect('feed:feed')
        else: # Kung ang pag -login ay hindi matagumpay,
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # Ito ang bahagi kung saan ina -update namin ang profile ng mga gumagamit
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # Kaya hindi na sila maaaring mag -log in muli ng ilang segundo
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Kaya ito ay medyo simple, mayroon kaming isang paraan upang mai -redirect sa dalawang kadahilanan ng view ng pagpapatunay kapag nilikha natin ito. Mayroon din kaming isang fallback kung sakaling ang gumagamit ay hindi nagdagdag ng isang numero ng telepono. Magdaragdag kami ng isang pangunahing view upang magdagdag ng isang numero ng telepono sa lalong madaling panahon at mag -log in gamit ang isang text message sa lalong madaling panahon. Una, kailangan namin ng isang madaling paraan upang magpadala ng isang text message mula sa aming code. Upang gawin ito, maaari tayong pumili mula sa isang bilang ng mga API, ngunit ang pinakamadali sa aking opinyon ay Twilio. Nag -aalok din sila ng mahusay na pagpepresyo para sa mas maliit na mga proyekto, pati na rin ang mga diskwento na bulk. Lumikha ng isang account sa Twilio.com, punan ang ilang mga detalye tungkol sa iyong proyekto, bumili ng isang numero ng telepono, at kopyahin ang iyong mga susi ng API sa iyong mga setting.py. Pagkatapos, idagdag ang code na ito sa ilalim ng isang bagong file, mga gumagamit/sms.py.

nano users/sms.py

# I -import ang lahat ng mga kinakailangang pakete
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

# Ang code na ito ay nagpapadala ng teksto kasama ang 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())

# Isang katulong na pag -andar upang makakuha ng isang numero na may napakaraming mga numero
def get_num_length(num, length):
    n = ''
    for x in range(length):
        n = n + str(num)
    return int(n)

# Ipadala ang teksto upang mapatunayan ang gumagamit
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)))

# Magpadala ng isang gumagamit ng anumang teksto gamit ang pagpapaandar na ito
def send_user_text(user, text):
    send_text(user.profile.phone_number, text)

# Patunayan ang code gamit ang pagpapaandar na ito
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

# Patunayan ang oras
def check_verification_time(user):
    result = user.profile.mfa_code_expires > timezone.now()
    return result
Siguraduhing baguhin ang iyong mga setting nang naaangkop, pagdaragdag ng mga linyang ito sa iyong mga susi:

# Siguraduhing kopyahin ang mga ito mula sa iyong Dashboard ng 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 # Ang bilang ng mga minuto ang pahina ng TFA ay aktibo sa sandaling ma -instantiate
Una, kakailanganin namin ang mga form para sa aming dalawang kadahilanan ng mga view ng pagpapatunay. Pag -edit ng mga gumagamit/forms.py, idagdag ang sumusunod na code.

# ... halaga
from django import forms

# Isang form para sa pagpasok ng aming numero ng telepono
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

# Isang form para sa pagpapatunay
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.'
    }
Susunod, lumikha tayo ng mga pananaw sa mga gumagamit/view.py

# ... halaga
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})
Kakailanganin din namin ang mga template para sa parehong mga pananaw na ito. Idagdag muna natin ang template ng MFA.

nano users/templates/users/mfa.html
Idagdag ang html code na ito sa template
 
{% 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 %}
 
Ito ay medyo paliwanag sa sarili. Ang form ay nagpapadala ng alinman sa isang code o isang walang laman na code, at mapapansin mo sa view na ipinapadala namin ang code kung nakatanggap kami ng isang walang laman na code. Pagkatapos ay mayroon lamang kaming dalawang mga pindutan ng isumite, at sa ganitong paraan maaari naming ipadala ang code gamit ang alinman sa pindutan. Susunod, magdagdag kami ng isang simpleng form upang magdagdag ng isang numero ng telepono.

nano users/templates/users/mfa_onboarding.html
Idagdag ang sumusunod na 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 %}
 
Ang form na ito ay mas simple, nag -render lamang ito ng form ng numero ng telepono na nilikha namin at hinahayaan ang gumagamit na magdagdag ng isang numero ng telepono. Mukhang maganda ito! Hangga't maayos na naka -set up ang lahat, dapat nating magpadala ng mga mensahe, at i -log ang gumagamit gamit ang kanilang numero ng telepono sa sandaling idagdag namin ang mga pattern ng URL. Ang huling bagay na kailangan naming i -set up ay isang view ng profile upang matiyak na mababago ng gumagamit ang kanilang numero ng telepono nang hindi naka -log in. Gayundin, sa huli ay nais naming magdagdag ng isang pagpipilian na "ihinto upang huminto", upang ang gumagamit ay maaaring mag -text "Tumigil" upang mag -opt out sa mga text message sa hinaharap. Magdagdag tayo ng isang view ng profile sa mga gumagamit/view.py. Ang view na ito ay i -update ang bio, email, username, at numero ng telepono, pati na rin payagan kaming paganahin ang pagpapatunay ng maraming kadahilanan. Una, kakailanganin namin ng dalawang higit pang mga form sa mga gumagamit/form.py

# ... halaga
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']
Susunod, maaari kaming lumikha ng isang view upang magamit ang parehong mga form na ito. I -edit ang mga gumagamit/view.py at idagdag sa view.

# Idagdag ang mga import na ito
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)
Kakailanganin din namin ng isang template para sa view na ito.

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 %}
 
Mapapansin mo na ito ay isang medyo simpleng form, ngunit may ilang JavaScript sa loob nito na awtomatikong nai -post ang mga nilalaman ng form habang na -update ang mga ito. Ito ay kapaki -pakinabang na magkaroon, kaya nagagawa mong gumawa ng mga pag -edit nang hindi kinakailangang pindutin ang isumite sa bawat oras. Susunod, kailangan namin ng mga URL na kumakatawan sa lahat ng mga pananaw na ito sa mga gumagamit ng URL patters. I -edit ang mga gumagamit/urls.py at idagdag ang code na ito:

# ... Nakaraang code, pag -import
from django.urls import path
from . import views

app_name='users'

urlpatterns = [
# … Mga pattern ng URL na dati naming ipinasok, idagdag ang susunod na tatlong linya
    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'),
]
Ngayon ay isang magandang panahon upang subukan ang aming proyekto. Ngunit una, magpatakbo tayo ng isa pang backup.

backup
At patakbuhin ang server. Bago kami mag -deploy sa isang Linux server, magandang ideya na paganahin ang dalawang kadahilanan ng pagpapatunay sa account. Gagawin namin ito sa aming URL ng profile,/mga gumagamit/profile/, at suriin ang kahon upang paganahin ang pagpapatunay pagkatapos pumasok sa aming numero ng telepono, at pagkatapos ay isumite ang form.

python manage.py runserver localhost:8000
Bisitahin ang webpage sa pamamagitan ng pagpunta sa iyong web browser, gumagamit ako ng Google Chrome sa halimbawang ito, at pagpasok sa URL https: // localhost: 8000/account/profile/ Magagawa mong mag -log in kung kinakailangan at paganahin ang dalawang kadahilanan ng pagpapatunay. Ang proyektong ito ay nangangailangan ng isang server upang tumakbo upang maaari itong talagang magpadala ng mail. Ngunit una, kailangan namin ng isang paraan upang makita ang mga pagkakamali. Mapapansin mo na kung pinapatakbo mo ang server sa debug mode, na may mga setting.debug na katumbas ng totoo, awtomatikong nagpapakita ang server ng mga error. Upang ipakita ang mga pagkakamali nang hindi gumagamit ng mode ng debug, na hindi ligtas sa isang server ng produksyon, dapat kaming magdagdag ng isang view para dito. Ang pinakamahalagang mga pagkakamali na kailangan nating hawakan ay: Error 500 - Isang problema sa aming code Error 404 - Isang pahina na hindi natagpuan (Broken URL) Error 403 - Isang pahintulot na tinanggihan ang error Magdagdag tayo ng isang bagong app upang mahawakan ang mga error na ito, na tinatawag na mga error.

python manage.py startapp errors
Idagdag ito sa mga setting.py tulad ng ginawa namin dati, sa setting ng naka -install na_apps, at magsimula sa pamamagitan ng pagdaragdag ng mga sanggunian sa ilang mga view sa app/urls.py, kung saan ang app ay ang pangalan ng iyong proyekto ng Django.

handler404 = 'errors.views.handler404'
handler500 = 'errors.views.handler500'
handler403 = 'errors.views.handler403'
Ito ang kailangan namin bukod sa mga view ng error, mga template at kaunting middleware. Tukuyin natin ang mga ito tulad ng:

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

# Lumikha ng iyong mga pananaw dito.
@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.'})
Susunod, tukuyin natin ang middleware upang mahawakan ang mga error na ito. Gagawin namin ito sa pamamagitan ng unang pagdaragdag sa mga middleware_classes sa mga setting.py, kasama ang pangalan ng aming middleware.

MIDDLEWARE_CLASSES = [
    # ... Nakaraang middleware
    'errors.middleware.ExceptionVerboseMiddleware,
]
Susunod, idagdag natin ang middleware.

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.')
Nagdaragdag kami ng isang function upang makuha ang kasalukuyang pagbubukod sa pamamagitan ng paggamit ng isang threading lokal, na tumutulong sa amin na masubaybayan ang anumang mga pagkakamali sa aming code. Sa mga tuntunin ng mga template, kailangan lamang natin ang isa, dahil dinamikong tinukoy namin ang pamagat sa view. Ang template ay kailangan lamang i -render ang pamagat at "bakas", ang aming error na traceback mula sa konteksto.

nano errors/templates/errors/error.html
 
{% extends 'base.html' %}
{% block content %}
<h1>{{ pagetitle }}</h1>
<p>{{ trace }}</p>
{% endblock %}
 
Ito ang aming pinakasimpleng template pa, ngunit ganoon kadali ang makita ang mga pagkakamali sa aming proyekto. Susunod, huwag paganahin ang pag -debug sa mga setting.

nano app/settings.py
Hanapin ang linya na ito kung saan ito nakatakda sa totoo, at baguhin ito sa maling

DEBUG = False
Sige at i -backup ang app ngayon. Handa kaming mag -deploy sa isang remote na Linux server, at panatilihin ang pagdaragdag ng mga tampok mula doon.

sudo backup
Bago namin mai -post ang code na ito sa isang server, dapat nating isaalang -alang na maaaring may ilang mga isyu sa code. Depende sa kaso, ang mga site na tumatanggap ng impormasyon na nai -post sa kanila ay magkakaroon ng mga isyu sa spam na nai -post at nahihirapang alisin ang spam. Hindi ito dapat mangyari kaagad, ngunit kung nangyayari ito, susuriin natin kung paano awtomatikong katamtaman ang spam sa site at gawing mas mahirap para sa mga robot na ma -access ang site, kasama kung paano i -deactivate ang mga account ng gumagamit, at i -verify ang pagkakakilanlan ng isang gumagamit sa Isang pag -scan ng kanilang ID o isang biometric scan, tulad ng isang fingerprint o pagkilala sa mukha. Sa pagtingin sa halimbawa ng multi factor na sinuri namin, sa paggawa, maaaring magkakaiba ang mga bagay. Pansinin kung paano namin ang paglilimita sa mga logins, at pag -expire ng mga token. Kung ang mga robot ay nag -access sa isang site, ang dalawang kadahilanan ng pagpapatunay ay maaaring maging mas mahirap dahil maaari silang magpasok ng mga code sa parehong oras ang gumagamit. Upang labanan ito, gumamit tayo ng isang modelo sa mga modelo ng gumagamit, na nagpapahayag kung paano kami nakikipag -ugnay sa site kung kailan tayoAng pagpapatunay gamit ang multi factor na pagpapatunay sa isang numero ng telepono. Magdaragdag din kami ng isang pagpipilian upang mapatunayan sa email. Magsimula sa pamamagitan ng pag -edit ng mga modelo ng gumagamit

nano users/models.py
Ito ang dapat na hitsura ng modelo na ating idaragdag. Hindi namin kailangan ng anumang mga pamamaraan, mga variable lamang upang mag -imbak ng isang ID, ang gumagamit, ang timestamp, pag -expire, haba at pagtatangka laban sa anumang multi factor na pagpapatunay (isang code tulad ng 123456 na ipinadala sa isang telepono o email).

# Isang pangunahing token na ginamit upang mag -log in sa website
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)
Magdagdag din tayo ng isang pribilehiyo sa aming gumagamit, at manu -mano naming itatakda ito para sa ngayon, bago sa huli ay lumipat sa awtomatikong pag -enrol ng mga pribadong gumagamit. Sa mga modelo ng gumagamit, idagdag ang linya na ito sa profile:

    vendor = models.BooleanField(default=False)
Tulad ng anumang mga pagbabago sa database, kailangan nating gumawa ng paglipat at ilipat ang database anumang oras na i -edit namin ang isang file.py file sa django. Tandaan, upang gawin ito ay ginagamit muna namin ang mapagkukunan (kung hindi pa ito ginamit mula nang bukas ang terminal) at pagkatapos ay python management.py upang gumawa ng paglipat at lumipat.

cd project-directory-you-named # (kung kinakailangan)
source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
Sa ngayon, maaari kang magpalista ng anumang mga account na nilikha mo bilang mga vendor sa pamamagitan ng paggamit ng shell.

python manage.py shell
from users.models import Profile
p = Profile.objects.get(user__username='Charlotte')
p.vendor = True
p.save()
exit()
Ngayon, i -evolve natin ang aming view ng pagpapatunay ng multi factor upang magamit ang token na ito. Una, kailangan nating baguhin ang aming mga kagamitan sa MFA Helper. Gamit ang nano,

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

# Patunayan ang gumagamit gamit ang kanilang email o numero ng telepono
def mfa(request, username, usertoken):
    token = MFAToken.objects.filter(uid=username, expires__gt=timezone.now() + datetime.timedelta(seconds=30)).order_by('-timestamp').last() # Filter ang token sa pamamagitan ng halaga na naipasa sa URL (isang UUID)
    if not token: token = MFAToken.objects.create(user=User.objects.filter(profile__uuid=username).first(), uid=username, expires=timezone.now() + datetime.timedelta(seconds=115)) # Kung ang session na ito ay hindi nilikha, lumikha ito
    user = User.objects.filter(id=token.user.id).first() # Kunin ang gumagamit mula sa token
    if not user and request.user.is_authenticated: return redirect(reverse('feed:home')) # Kung napatunayan na sila, mag -log in
    if not user: raise PermissionDenied() # Itanggi kung walang nahanap na gumagamit
    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): # Suriin ang token ng may -akda
        auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Mag -log in sa gumagamit kung hindi pa sila naka -log in
        user.profile.mfa_expires = timezone.now() + datetime.timedelta(minutes=settings.LOGIN_VALID_MINUTES) # Magtakda ng isang pag -expire sa kanilang multi factor na pagpapatunay
        user.profile.save()
        return HttpResponseRedirect(next if next != '' else reverse('landing:landing')) # I -redirect ang gumagamit sa susunod na pahina
    if not user.profile.mfa_enabled: # Suriin kung pinagana ang MFA
        if not check_verification_time(user, token): # Suriin ang oras
            user.profile.mfa_enabled = False # I -clear ang numero ng telepono
            user.profile.enable_two_factor_authentication = True # Paganahin ang MFA
            user.profile.phone_number = '+1' # Huwag paganahin ang numero ng telepono
            user.profile.save() # I -save ang profile
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Mag -log sa gumagamit kung hindi pinagana ang kanilang 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): # Kung ang kahilingan ay isang kahilingan sa post
        form = TfaForm(request.POST) # I -instantiate ang form
        code = str(form.data.get('code', None)) # Kunin ang code
        if code and code != '' and code != None: # Siguraduhin na hindi ito walang laman
            token_validated = user.profile.check_auth_token(usertoken) # Suriin ang token ng may -akda
            p = user.profile
            is_verified = check_verification_code(user, token, code) # Suriin ang code
            p.mfa_authenticated = is_verified
            if token_validated: # Kung ang lahat
                if is_verified: # Ay nasa maayos
                    user.profile.mfa_enabled = True # Paganahin ang MFA (kung hindi pa pinagana)
                    user.profile.save()
                    auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Mag -log in sa gumagamit
                    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(): # Bumuo ng isang querystring para sa susunod na parameter (kung mayroon man)
                        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) # Redirect
                    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: # Kung ang token ay hindi wasto
                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: # Kung napakaraming mga pagtatangka
                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): # Ipadala ang email (o teksto)
                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('/'))
    # I -render ang form (para sa mga kahilingan sa pagkuha)
    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'})
Kapag nagdaragdag kami sa code na ito, tiyaking i -import ang function upang magpadala ng isang email. Sa tuktok ng file, ang view ng gumagamit (kasama ang iba pang mga pag -import), idagdag

from .mfa import send_verification_email as send_mfa_verification_email
Ngayon, kailangan nating isulat ang pagpapaandar na iyon bago gagana ang anuman dito. Dapat itong pahabain ang aming pagpapadala ng email function, at magpadala lamang ng isang email sa gumagamit gamit ang verification code.

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))
Kaya lahat ito ay gumagana nang mahusay, ngayon mayroon kaming isang multi factor na pagpapatunay ng sistema na nakasalalay sa isang numero ng telepono o email upang mag -log in. Ngunit kailangan din namin ng isang paraan upang alisin, o hindi bababa sa itago ang mga gumagamit na hindi nakikipagtulungan sa aming mga termino. Ang mga ito ay maaaring maging mga spammers, robot o sinumang hindi nangangahulugang mabuti para sa aming trabaho. Tingnan ang isang view na mayroon ako para sa pagsubaybay sa mga gumagamit sa aking website:

# halaga
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import user_passes_test
from .tests import is_superuser_or_vendor # Kailangan nating lumikha ng pagsubok na ito

@login_required
@user_passes_test(is_superuser_or_vendor)
def users(request):
    # Kumuha ng listahan ng mga gumagamit
    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', { # Ibalik ang mga gumagamit sa isang template
        'title': 'All Accounts',
        'users': User.objects.all(),
        'new_today': new_today,
        'new_this_month': new_this_month,
        'subscribers': subscribers
    })
Tandaan na ang code na ito ay gumagamit ng isang pagsubok, kakailanganin nating ipahayag ang pagsubok na ito sa isang pagsubok.Py file at i -import ito. Pag -edit ng mga gumagamit/pagsubok.Py, lumikha tayo ng pagsubok.

def is_superuser_or_vendor(user):
    return user.profile.vendor or user.is_superuser
Ito ay kasabay ng template ng mga gumagamit/gumagamit.html, na mukhang katulad nito:
 
{% 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 %}
 
Tandaan na ang template ay nagsasama ng isa pang template, mga gumagamit/_user.html. Kapag gumagamit ng isang template na may isang subtemplate at hindi gumagamit ng pagpapalawak, magandang ideya na magdagdag ng isang underscore (_) bago ang pangalan ng file upang mapalawak, upang makilala ang mga template. Tandaan na ito ay maraming Jinja, maaaring hindi mo nakuha ang lahat ng mga variable na ito na tinukoy. Ngunit ito ang hitsura ng aking code.
 
{% 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>
 
Kailangan din namin ng isa pang subtemplate, toggle_active.html. Ang template na ito ay dapat na isang form na nagbibigay -daan sa amin upang i -toggle kung ang isang gumagamit ay aktibo.
 
<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>
 
Kailangan din nating magdagdag ng isang view upang i -toggle ang aktibidad ng gumagamit, at naaangkop na mga pattern ng URL. Habang naroroon tayo, magdagdag tayo ng isang view upang tanggalin ang isang gumagamit kung sakaling kailanganin natin iyon.

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>')


# Halaga
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.views.generic import DeleteView

class UserDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = User
    success_url = '/' # Ang pag -redirect sa tagumpay ng URL
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        return context

    def test_func(self): # Pagsubok kung ang gumagamit ay superuser at may pahintulot na tanggalin
        user = self.get_object()
        if self.request.user != user and self.request.user.is_superuser:
            return True
        return False
Habang ito ay praktikal kung kinakailangan, ang pagtanggal ng isang gumagamit ay hindi dapat kinakailangan sa karamihan ng oras, maaari lamang nating i -toggle ang kakayahang makita ng mga gumagamit na bumibisita sa site kung kailangan nating tanggalin ang mga ito. Ang mga pattern ng URL na idinagdag namin ay ganito. Sa nano, i -edit ang mga gumagamit/urls.py at idagdag ang mga linyang ito:

nano users/urls.py
Ang mga linya ay dapat pumunta sa listahan ng mga landas sa mga view ng gumagamit, bago matapos ang "]" ngunit pagkatapos ng simula "[".

# …
    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'),
# …
Ngayon, tiyaking i -back up ang site upang mai -download mo ito sa web server ay magpapatuloy kaming magtrabaho. Mula sa linya ng utos,

sudo backup
Ngayon ay nai -back up ang aming site. Kaya ngayon mayroon kaming ilang mas kapaki -pakinabang na mga tampok. Ngunit ano ang tungkol sa malaking larawan dito? Ang code na ito ay hindi pa rin maa -access mula sa Internet, wala pa kaming mail server, at kailangan naming palawakin ang aming app upang isama ang komprehensibong proseso ng pag -verify pati na rin ang makinis na mga layout upang matulungan kaming galugarin ang site, kasama ang mga ligtas na protocol para sa pagpapatunay ng mga pribadong gumagamit . Makakarating tayo sa lahat ng ito. Ang pinakamahalagang bagay para sa ngayon ay makakakuha lamang ng code na ito sa online, na magagawa natin sa ilang mga linya lamang ng bash sa isang Ubuntu server. Kailangan mong magrenta ng isang server para dito, maliban kung mayroon kang isang server sa bahay at isang subscription sa internet sa negosyo na nagbibigay -daan sa iyo upang buksan ang mga port. Personal kong pinapatakbo ang aking website sa isang HP Z440 na naka -install sa aking apartment, ngunit karaniwang mas mura ito para sa mga pangunahing pangangailangan na magrenta ng isang virtual pribadong server (VPS). Tandaan na ang code na ating pinapatakbo ngayon ay medyo manipis, kakailanganin itong mapanatili at mapabuti bago tayoHanda nang gamitin kung ano ang kailangan nating bumuo ng isang produkto. Siguraduhin na mag -ingat sa kung ano ang gagawin mo sa Internet, tiyakin kung inilalagay mo sa publiko ang site na ito sa web sa isang Linux server, mayroon kang isang plano upang hadlangan ang mga hindi ginustong pakikipag -ugnay sa iyong website. Ito ay malamang na hindi magiging isang problema sa una, ngunit titingnan namin ang iba't ibang mga solusyon upang labanan ito, kabilang ang pag -aaral ng makina, artipisyal na katalinuhan at pangitain sa computer. Kapag ito ay naging isang problema, tumingin pa sa tekstong ito para sa isang solusyon. Sa mga tuntunin ng pag -upa ng isang VPS, maraming mga lugar na maaari mong puntahan. Ang Google Cloud ay may mga server ng VPS, Ionos, Kamatera, Amazon AWS, at higit pang mga tagapagkaloob ay nag -aalok ng mga solusyon sa cloud server na angkop sa aming mga pangangailangan. Kailangan mong mag -click sa kanilang mga form at pumili ng isang plano upang makapagsimula. Maaari kang sumama sa isang pangunahing plano sa anumang tagapagbigay ng serbisyo, ngunit siguraduhin na pinapayagan ka ng tagapagkaloob na buksan ang mga port ng port ng server ng port upang magpadala ng email (dapat itong port 587 at port 25), ang ilang mga tagapagkaloob ay hadlangan ang mga port na ito. Sa ngayon mayroon akongEST karanasan sa Ionos at Kamatera, pareho silang magpapahintulot sa akin na magpadala ng walang limitasyong email at ang kanilang pagpepresyo ay medyo mura. Makakonekta ka sa iyong bagong server sa isang protocol na tinatawag na SSH o Secure Shell, na nagbibigay -daan sa iyo upang malayuan ang interface sa server nang eksakto tulad ng iyong personal na computer, mula sa iyong personal na computer. Kapag na -set up mo ang server, ang hosting provider ay malamang na hihilingin sa iyo na magdagdag ng isang SSH key, o bibigyan ka nila ng isang username at password. Ang SSH key ay kung paano ka mag -log in sa server mula sa command line upang mai -edit ang code. Gamitin ang mga pagpipilian sa Ssh-keygen sa ibaba upang makabuo ng isang SSH

ssh-keygen
I -save ang file at i -overwrite ito kung kailangan mo, mabuti na paikutin ang iyong mga SSH key kung wala ka pa. Ngayon, maaari mong gamitin ang sumusunod na utos upang makita ang iyong SSH key. Gusto mong kopyahin ito sa iyong remote server upang magamit mo ito upang mapatunayan.

cat ~/.ssh/id_rsa.pub
Kung hindi ka nakakakita ng isang SSH key kapag nagta-type ng utos na iyon (isang mahabang string ng mga numero at titik na nagsisimula sa "SSH-RSA AAA"), subukang bumuo ng isang RSA key (mas ligtas sila, kaya pinapayuhan kong gamitin ang mga ito .) Ang sumusunod na code ay bubuo ng isang 4096 bit RSA SSH key.

ssh-keygen -t rsa -b 4096
Lumikha ng isang VPS na tumatakbo sa Ubuntu, gayunpaman plano mong gawin ito. Kapag lumikha ka ng isang VPS sa pamamagitan ng pag -click sa mga form sa website ng Mga Tagabigay (Kamatera.com, Ionos.com o Katulad), nais mong mag -log in. Upang gawin ito, gamitin ang utos ng SSH gamit ang iyong IP address (ang address Iyon ay parang xx.xx.xx.xx). Kailangan mo ring maging sensitibo sa default na username sa server na nilikha namin, halimbawa, Ubuntu.

ssh ubuntu@XX.XX.XX.XX
Maaari kang hilingin para sa isang password, kung tatanungin ka ng isang password, ipasok ito. Hindi namin gagamitin ang default na username, kaya magsimula tayo sa pamamagitan ng paglikha ng isang bagong gumagamit at pagdaragdag ng isang SSH key sa kanilang account. Magsimula tayo sa pamamagitan ng pagdaragdag ng isang bagong file ng sshd_config, na nagsasabi sa server kung paano gamitin ang SSH.

nano sshd_config

# Ito ang file ng pagsasaayos ng system ng SSHD server.  Kita n'yo
# sshd_config (5) para sa karagdagang impormasyon.

# Ang sshd na ito ay pinagsama sa landas =/usr/lokal/sbin:/usr/lokal/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

# Ang diskarte na ginamit para sa mga pagpipilian sa default na sshd_config na ipinadala sa
# Ang OpenSSH ay upang tukuyin ang mga pagpipilian sa kanilang default na halaga kung saan
# Posible, ngunit iwanan ang mga ito ay nagkomento.  Ang mga hindi naaangkop na pagpipilian ay override ang
# Default na halaga.

# Port 22
# AddressFamily anumang
# Listahan ng Address 0.0.0.0
# Makinig Adress ::

# Hostkey/etc/ssh/ssh_host_rsa_key
# Hostkey/etc/ssh/ssh_host_ecdsa_key
# Hostkey/etc/ssh/ssh_host_ed25519_key

# Ciphers at Keying
# REKEYLIMIT Default Wala

#  Logging
# SYSLOGFACILITY AUTH
# Impormasyon sa Loglevel

# Pagpapatunay:

# Logringracetime 2m
# Permitrootlogin Prohibit-Password
# Strictmode oo
# MaxauthTries 6
# Maxessions 10

PubkeyAuthentication yes

# Asahan.
AuthorizedKeysFile	.ssh/authorized_keys .ssh/authorized_keys2

# AwtorisadoPrincipalsfile Wala

# AwtorisadoKeysCommand wala
# Awtorisadokeyscommanduser walang tao

# Para sa ito upang gumana kakailanganin mo rin ang mga host key sa/etc/ssh/ssh_nnown_hosts
# Hostbasedauthentication no
# Baguhin sa Oo kung hindi ka nagtitiwala ~/.ssh/kilala_host para sa
# Hostbasedauthentication
# Hindi pinapansin ang mga hindi kilalang tao
# Huwag basahin ang mga file ng gumagamit ~/.rhost at ~/.Shost file
# Ignorerhost oo

# Upang hindi paganahin ang mga naka -tunn na malinaw na mga password sa teksto, magbago sa wala rito!
PasswordAuthentication no
# Permitempsasswords no

# Baguhin sa Oo upang paganahin ang mga password ng hamon-tugon (mag-ingat sa mga isyu sa
# ilang mga module at thread)
KbdInteractiveAuthentication no

# Mga pagpipilian sa Kerberos
# Kerberosauthentication no
# Kerberosorlocalpasswd Oo
# KerberosticketCleanup Oo
# Kerberoscotted Rod no

# Mga pagpipilian sa GSSAPI
# GSSAPIAUTHENTICATION NO
# GSSAPICLEANUPCREDENTIALS Oo
# GSSAPISTRICTACTORCHECK Oo
# GSSAPIKEYEXCHANGE NO

# Itakda ito sa 'Oo' upang paganahin ang pagpapatunay ng PAM, pagproseso ng account,
# at pagproseso ng session. Kung pinagana ito, ang pagpapatunay ng PAM
# payagan sa pamamagitan ng KBDinteractiveAuthentication at
# PasswordAuthentication.  Depende sa iyong pagsasaayos ng PAM,
# Ang pagpapatunay ng PAM sa pamamagitan ng kbdinteractiveauthentication ay maaaring lumampas
# Ang setting ng "Permitrootlogin nang walang-Password".
# Kung nais mo lang ang PAM account at session na mga tseke na tumakbo nang wala
# Pagpapatunay ng PAM, pagkatapos ay paganahin ito ngunit itakda ang passwordAuthentication
# at Kbdinteractiveauthentication sa 'hindi'.
UsePAM yes

# Allowagentforwarding oo
# Allowtcpforwarding oo
# Gatewayports no
X11Forwarding yes
# X11displayoffset 10
# X11uselocalhost oo
# Permittty oo
PrintMotd no
# PRINTLASTLOG Oo
# TCPEKEPALIVE Oo
# Permittuen environment sa
# Naantala ang compression
# Agwat ng kliyente 0
# ClientaliveCountMax 3
# Ginamitns sa
# Pidfile /run/sshd.pid
# MaxStartups 10: 30: 100
# Pemittunl no
# Chrootdirectory wala
# Bersyon Addendum Wala

# Walang default na landas ng banner
Banner /etc/banner

# Payagan ang kliyente na ipasa ang mga variable na kapaligiran ng lokal
AcceptEnv LANG LC_*

# Override default ng walang mga subsystem
Subsystem	sftp	/usr/lib/openssh/sftp-server

# Halimbawa ng mga overriding setting sa isang per-user na batayan
# Itugma ang gumagamit anoncvs
# X11forwarding no
# Allowtcpforwarding no
# Payagan sa
# Forcecommand CVS server
PermitRootLogin no
Tandaan, Ctrl+X at Y upang mai -save ang file. Susunod, sumulat tayo ng isang pangunahing script na tinatawag na Initialize (lahat sa default na direktoryo ng bahay ng aming gumagamit).

nano initialize
Idagdag ang mga linya na ito sa file, pinapalitanGamit ang iyong SSH key na natagpuan mo gamit ang pusa. (.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
Upang maglakad ka sa pamamagitan ng file na ito, simulan natin ang linya sa pamamagitan ng linya. Ang unang linya ay nagsasabi sa tagatala na ito ay isang script ng bash. Pagkatapos ay nag -install kami ng mga dependencies, pagkopya ng sshd_config sa tamang direktoryo, pag -restart ng SSH, pagbuo ng mga susi ng SSH para sa ugat, pagdaragdag ng 'koponan' ng gumagamit (maaari kang pumili ng isang pangalan na gusto mo para dito, gamitin ang utos ng adduser gamit ang kanilang pangalan at may kapansanan na password para sa ngayon). Nagdaragdag din kami ng koponan sa pangkat ng sudo, bumuo ng kanilang SSH key, idagdag ang aming susi sa mga awtorisadong susi at ang kanilang mga, at i -print ang kanilang susi. Ang bagong gumagamit na ito ay kung paano kami mag -log in sa site. Sa isang bagong terminal, sige at buksan muli ang server.

ssh team@XX.XX.XX.XX
Hindi mo dapat kailanganin ang isang password sa oras na ito, na mayroon kang isang SSH key. Hindi rin namin pinagana ang pag -login gamit ang password upang mapanatiling ligtas ang site. Ngayon, ang server na ito ay nagsisimula nang ganap na blangko na walang impormasyon tungkol dito. Magsimula tayo sa pamamagitan ng pag -clone ng aming proyekto mula sa Git upang ma -download at patakbuhin ito sa remote machine. Sa remote server na konektado sa SSH, i -print muna ang iyong SSH key:

cat ~/.ssh/id_rsa.pub
Susunod, i -paste ang susi na ito sa mga setting ng git tulad ng ginawa namin bago upang i -set up ang aming git sa git. Maaari na nating i -clone nang direkta ang aming proyekto sa server. Siguraduhin na na -back up mo muna ang proyekto nang lokal kaya nasa GIT server upang i -download.

git clone git://github.com/you/yourproject.git
Perpekto. Ngayon lahat ng mga file ay narito. Makikita natin ang mga ito sa LS

ls
Ngayon, simulan nating i -set up ang server. Una, kopyahin ang iyong direktoryo ng proyekto sa isang simple, hindi malilimot na pangalan na gagamitin namin para sa proyekto.

cp -r yourproject whatyoucalledit
Kung saan ang "WhatYoucalledit" ay ang bagong pangalan ng iyong proyekto. Susunod, kakailanganin nating bumuo ng isang pangunahing utility upang mai -set up ang server. I -save namin ang utility na ito at gagamitin ito sa hinaharap. Upang mabuo ang utility na ito, lumikha tayo ng isang binary ng gumagamit upang tukuyin kung paano namin i -edit ang isang script. Gamit ang Bash, I -edit/usr/bin/ascript

sudo nano /usr/bin/ascript
Siguraduhing gumamit ng sudo doon upang mayroon kang mga pahintulot upang mai -edit ang file. Sa file, idagdag ang mga linyang ito:

# !
if [ ! -f /usr/bin/$1 ]; then
    sudo touch /usr/bin/$1
    echo "# !
    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
Alalahanin ang script na ito ay tumatagal ng isang argumento, ang pangalan ng script, bilang $ 1. Una itong susuriin kung umiiral ang file, o kung hindi man ay nilikha ito, idinagdag ang unang linya upang ipahayag ang script ay bash, binabago ang mga pahintulot nito, na -edit ito, at idinagdag ang pangalan nito sa / ay lumilikha. Kung mayroon na ang file, baguhin lamang ang mga pahintulot at i -edit ito. I -save ang file, at sa susunod ay babaguhin natin ang mga pahintulot nito. Hangga't ginagamit namin ang script na ito, hindi na natin kailangang gawin iyon muli.

sudo chmod a+x /usr/bin/ascript
Perpekto. Ngayon lumikha tayo ng isang script na tinatawag na Setup. Una, hindi upang mapuspos ka, ngunit tingnan kung ano ang hitsura ng aking script sa pag -setup. Maglalakad kami sa kung ano ang dapat magmukhang script na ito sa iyong proyekto, hindi mo kakailanganin ang lahat sa aking script upang magsimula.

# !
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
# sudo chmod a+x script/useretup
# ./scripts/usersetup
# SSH-Keyen
# Direktoryo ng Proyekto
DIR="/home/team/femmebabe"
USER="team"
# Mga utos ng log
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
# Nano config
echo "set tabsize 4" >> .nanorc
echo "set tabstospaces" >> .nanorc
# Git config
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
# I -update at i -install
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
# Paganahin ang Camav Antivirus
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Itakda ang hostname
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname localhost
# Setup 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;"
# Setup backup database
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
# Hindi pinagana ang mga iPatable
echo "Configuring firewall"
sudo iptables -P INPUT ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -F
sudo iptables-save
# I -install ang 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
# Setup 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
# Lumikha ng 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
# Setup Virtuealenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
# Kumuha at bumuo ng mga dependencies
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
# Itakda ang mga patakaran sa firewall
cd $DIR
# I -install ang mga dependencies ng 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 I-install ang OpenCV-python == 4.5.5.64
# PIP I-install ang 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
# I -install ang 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
# Patakbuhin ang Certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email jasper.camber.holton@gmail.com
# I -reload ang Mail Server
sudo systemctl restart opendkim postfix dovecot
# Kopyahin ang mga certs
# sudo cp /etc/letsencrypt/live/femmebabe.com/privkey.pem privkey.pem
# sudo cp /etc/lettesencrypt/live/femmebabe.com/cert.pem cert.pem
# Patch
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"
# Itakda ang mga setting ng gumagamit
sudo gpasswd -a www-data users
# Magtakda ng mga pahintulot
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# SUDO CHOWN -R Team: Mga Gumagamit/Var/Run/
# SUDO CHOWN ROOT: 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: mga gumagamit 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
# Kopyahin ang config at magtakda ng mga pahintulot
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
# Pag -setup ng database
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"
# I -iniksyon ang PAM config at alisin ang mga faulty ssh config
# Sudo sed -i '' -at $ d '/etc/pam.d/sshd
# Sudo sed -i '' -at $ 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
# Kopyahin ang mga script ng bin at magtakda ng mga pahintulot
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
# I -reload at paganahin ang mga serbisyo
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
# Paganahin ang mga module ng 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
# Huwag paganahin ang default na site
sudo a2dissite 000-default
sudo a2dissite 000-default-le-ssl
# Paganahin para sa site
sudo a2ensite femmebabe-le-ssl
# I -reload ang daemon at i -restart ang Apache, Postfix at Opendkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
sudo systemctl start daphne
# Magtakda ng mga pahintulot
sudo chown -R :www-data /var/www/
sudo chown -R :www-data /var/www/.deepface
# Pag -configure ng Swap
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
# Init Caption Engine
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
# Setup 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
# Ipakita ang IPv6 at Opendkim para sa pagsasaayos ng domain
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}'
# Nakumpleto ang pag -setup
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."
Iyon ay maraming pag -setup! Sa madaling sabi, ang mga nag -log ng code na ito ay nag -uutos, nag -configure ng nano at git, mga kopya sa mga file, pag -download at pag -install ng mga packages ng ubuntu apt, python dependencies, na -configure ang postfix, na -configure ang postgreSQL (ang database server) at naglo -load ng database, na -configure ang UFW (isang hindi kumpletong firewall), Hindi pinapagana ang mga iptables, nag -download ng isang antivirus, gumagawa ng mga direktoryo, dependencies ng clones, Nag -install ng mga sertipiko at nagtatakda ng server, nag -install ng pagsasaayos, nagsisimula at nagbibigay -daan sa Sever, naglalaan ng pagpapalit, nagtatakda ng mga pahintulot, at mga pag -print ng IP, IPv6 address at Opendkim key. Medyo simple, ngunit mukhang maraming code. Hindi namin kakailanganin ito dahil wala kaming mga dependencies, hindi kami gumagamit ng kintsay, kintsay o daphne, ngunit mai -install namin ang ilan sa mga ito upang makapagsimula. Pansinin na ang code na ito ay may domain na idineklara nang maraming beses. Kailangan din nating bumili ng isang domain name (na kung saan ay isang maliit na taunang bayad). Inirerekumenda ko ang Squarespace para sa pagbili ng isang domain, ang kanilang layout aymadaling maunawaan at madaling gamitin. Maaari kang bumili ng anumang domain na iyong pinili, ngunit gumagamit ako ng domain femmebabe.com sa halimbawang ito. Kapag bumili ka ng isang domain, magtungo sa Squarespace DNS Configuration Panel at magdagdag ng isang record na tumuturo sa iyong domain sa server sa pamamagitan ng IP address. Ito ay dapat magmukhang ganito: @ A xx.xx.xx.xx Sa @ operator bilang host, na nangangahulugang lahat ng mga subdomain sa ilalim ng domain na ito at ang root domain ay lahat ay mag -redirect sa server. Marami pang mga talaan upang ipahayag, ngunit maaari kaming magpatuloy sa mga ito sa sandaling handa kaming magpadala ng mail. Tandaan, maaaring tumagal ng ilang araw bago ka matagumpay na magpadala ng mail mula sa server. Ang mga tala ng DNS na itinatakda namin ay maglaan ng oras upang magpalaganap. Pa rin, ang tanging talaang kailangan nating simulan ay isang talaan. Kaya ngayon maaari nating punan ang script sa ibaba ayon sa aming proyekto at patakbuhin ito. Magsimula tayo sa isang mas maliit na script ng pag -setup upang mai -install lamang kung ano ang kailangan natin para sa isang pangunahing pag -unlad. Hindi pa namin gagamitin ang napakaraming dependencies o postgresql pa, tayo langMag -up ng isang pangunahing HTTP server at mag -alala tungkol sa pagpapatunay nito kapag tapos na iyon. Tandaan, upang makakuha ng isang sertipiko ng HTTPS at patakbuhin nang ligtas ang server, kakailanganin naming bumili ng isang domain kasama ang pag -upa ng isang server. Sa ngayon, palitan ang "koponan" sa file na ito na may pangalan ng iyong gumagamit, "dir" gamit ang direktoryo ng iyong proyekto, at ibigay ang iyong email at domain sa mga <> tag. Bilang karagdagan, bago natin patakbuhin ang code na ito, kailangan nating baguhin ang mga setting sa firewall na sinusuportahan ng hosting provider, kung mayroon man. Karaniwan ito ay nasa tab na 'Networks' ng iyong hosting provider, o kung ikaw ay nagho -host sa sarili, nasa seksyon ng 'port forwarding' ng iyong router. Gusto mo ring mag -set up ng isang static na IP sa pamamagitan ng iyong router gamit ang address ng iyong server machine, kung gumagamit ka ng self hosting. Kailangan mong buksan ang mga sumusunod na port para sa Read/Writing Access. 22 (ssh) 25 (mail) 587 (mail) 110 (mail client) 80 (http) 443

# !
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
DIR="/home/team/<yourproject>"
USER="team"
# Mga utos ng log
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
# Nano config
echo "set tabsize 4" >> .nanorc
echo "set tabstospaces" >> .nanorc
# Git config
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
# I -update at i -install
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
# Paganahin ang Camav Antivirus
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Itakda ang hostname
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname femmebabe
# Setup backup database
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
# Hindi pinagana ang mga iPatable
echo "Configuring firewall"
sudo iptables -P INPUT ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -F
sudo iptables-save
# Setup Virtuealenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
pip3 install -r requirements.txt
# I -install ang 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
# Patakbuhin ang Certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email <youremail>@gmail.com
# Itakda ang mga setting ng gumagamit
sudo gpasswd -a www-data users
# Magtakda ng mga pahintulot
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# SUDO CHOWN -R Team: Mga Gumagamit/Var/Run/
# SUDO CHOWN ROOT: 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 ./
# I -reload at paganahin ang mga serbisyo
echo "Enabling services"
sudo systemctl daemon-reload
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Paganahin ang mga module ng 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
# I -reload ang daemon at i -restart ang Apache, Postfix at Opendkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
# Ipakita ang IPv6 at Opendkim para sa pagsasaayos ng domain
echo "COPY the below information to domain configuration."
hostname -I
ip a | grep inet
ip -6 addr | grep "scope link"
Bago patakbuhin ang code na ito, siguraduhin na ang domain na iyong binili ay konektado sa server. Upang gawin ito, buksan ang isang terminal sa iyong lokal na makina, at patakbuhin ang utos na ito gamit ang iyong domain:

ping femmebabe.com # Ipasok ang iyong domain dito, pagkatapos ng ping
Kung ang lahat ay mukhang maayos at ang server ay nagpapadala ng mga tugon, handa kaming patakbuhin ang script at mag -install ng mga pakete pati na rin magsimula, paganahin at patunayan ang aming Apache server. Hindi ito lahat ng pag -setup na kinakailangan upang i -configure ang Postfix, titingnan namin ang pag -setup na iyon sa ibang pagkakataon. Sa ngayon, patakbuhin ang setup code na ito at dapat itong tumagal ng ilang minuto upang mai -install at patunayan ang iyong server. Muli, siguraduhing palitan ang pangalan, email at domain name sa script ayon sa pangalang binili mo. Ngayon na ang server ay ipinagkaloob, maaari kang pumunta sa URL sa anumang web browser at suriin upang matiyak na ang server ay tumatakbo sa HTTPS. Kung hindi, subukang maghintay ng kaunti habang ang mga tala ng DNS ay makahabol at pagkatapos ay patakbuhin ang sumusunod na utos upang muling suriin ang sertipikasyon ng sertipikasyon:

sudo certbot --apache --non-interactive --agree-tos --domains <domain>.com --email <youremail>@gmail.com
Hangga't na -configure mo nang tama ang lahat, dapat mong ma -access ang default na pahina ng Apache upang malaman lamang ang iyong code ay gumagana at nagpapakita ng isang live na webpage. Susunod, i -edit natin ang mga setting.py upang baguhin ang aming default na debug mode sa paggawa. I -configure din namin ang domain sa mga setting, pati na rin ang mga panloob na IP.

nano yourproject/settings.py
Sa mga setting, baguhin/idagdag ang mga linyang ito.

DEBUG = False

# Site Config
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',
]
Ngayon, kakailanganin nating i -configure ang Apache2. I -edit natin ang config file na ilalagay namin sa linyang ito:

sudo nano /etc/apache2/sites-available/femmebabe-le-ssl.conf
Ang config file na ito ay dapat magkaroon ng aming domain name sa loob nito, at ang pangalan ng gumagamit at proyekto. Gumagamit ako ng domain name femmebabe.com, ang username team, at ang pangalan ng proyekto na 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>
Siguraduhing palitan ang pangalan ng proyekto, direktoryo, at domain sa halimbawang code na ito kapag na -configure ang iyong server. Ngayon, kakailanganin nating huwag paganahin ang default na site. Magagawa ito gamit ang bash.

sudo a2dissite 000-default-le-ssl
sudo a2dissite 000-default
sudo a2dissite default-ssl
Susunod, maaari naming paganahin ang default na site at i -reload ang Apache2, gamit din ang bash. Tandaan na palitan ang femmebabe sa pangalan ng file na ipinahayag mo kapag nag-edit sa/etc/apache2/site-magagamit/.

sudo a2ensite femmebabe-le-ssl
sudo systemctl reload apache2
Bumalik sa iyong domain sa Navbar. Dapat mong makita ang site na na -configure mo sa iyong web browser. Binabati kita! Kung hindi mo ito nakikita, maaaring kailanganin mong gumawa ng ilang mga pagbabago. Maingat na suriin ang mga setting sa iyong proyekto, pagsasaayos ng Apache, at tiyaking wala kang anumang mga pagkakamali, at patakbuhin ang mga sumusunod na utos upang suriin ang proyekto para sa mga pagkakamali.

cd projectname
source venv/bin/activate
python manage.py check
Kung mayroon kang mga pagkakamali sa iyong proyekto sa Python, bakas ang mga ito sa kung nasaan sila at ayusin ito. Maaaring hindi mo makita ang lahat ng iyong mga pagkakamali depende sa kung nasaan sila, kaya kung mayroon kang isang error na nagsasabing "populate ay hindi muling pagsasaayos", i -edit ang sumusunod na file sa virtual na kapaligiran, registry.py, upang ilantad ang error.

nano venv/lib/python3.12/site-packages/django/apps/registry.py
Mag -scroll sa linya 83, kung saan ang error na runtime na ito ay itinaas (itaas ang runtimeError ("populasyon () ay hindi reentrant")), at magdagdag ng isang puna bago ang linyang ito, pagkatapos ay idagdag, na may parehong indentation, self.app_configs = {}. Ganito ito:

            if self.loading:
                # Pigilan ang mga tawag sa reentrant upang maiwasan ang pagpapatakbo ng appConfig.ready ()
                # Mga pamamaraan ng dalawang beses.
# Itaas ang RuntTimeError ("Populate () ay hindi reentrant")
                self.app_configs = {}
            self.loading = True
Maaari mong suriin muli ang proyekto at ilantad ang error.

python manage.py check
Pagkatapos ay maaari mong makita ang error at ayusin ito. Kapag naayos mo na ito at ang code ay nag -iipon ng walang mga pagkakamali, tiyaking baguhin ang file upang maging ganito:

            if self.loading:
                # Pigilan ang mga tawag sa reentrant upang maiwasan ang pagpapatakbo ng appConfig.ready ()
                # Mga pamamaraan ng dalawang beses.
                raise RuntimeError("populate() isn't reentrant")
# self.app_configs = {}
            self.loading = True
Sa kondisyon na ang server ay online, kapag gumawa kami ng anumang karagdagang mga pagbabago dito, kailangan nating gamitin ang sumusunod na utos upang i -reload ang server:

sudo systemctl reload apache2
Galing! Ngunit ano ang tungkol sa pagpapadala ng mail? Upang simulan ang pagpapadala ng email, kailangan muna nating i -update ang pagsasaayos ng domain. Ito ay dapat na nasa iyong DNS panel sa Squarespace, o anumang rehistro ng pangalan ng domain na iyong pinili. Kailangan din nating mag -install at magdagdag ng pagsasaayos, at magpatakbo ng ilang mga utos. Una, makuha natin ang address ng IPv6 ng server. Bubuksan namin ang iyong DNS at idagdag ang mga tala. Upang makuha ang address ng IPv6 ng server, gamitin ang utos na ito:

ip -6 addr
Ngayon, maaari naming idagdag ang mga sumusunod na talaan sa mga setting ng DNS. Ganito ang hitsura ng aking mga tala. Gayunpaman, para sa iyong mga tala, dapat mong palitan ang IP address sa iyong IP (hindi 75.147.182.214, akin iyon). Idagdag din ang iyong domain sa lugar ng femmebabe.com, pati na rin ang iyong IPv6 address na natagpuan sa nakaraang utos (hindi mo magagamit ang minahan, FE80 :: 725A: FFF: FE49: 3E02). Huwag mag -alala tungkol sa Domainkey para sa ngayon, nilikha ito kapag nag -set up kami ng Postfix, ang mail server, na may Opendkim, at i -print ang susi. I -configure namin ito ang huling. @ A N/a 75.147.182.214 @ MX 10 femmebabe.com @ PTR N/a femmebabe.com @ Txt N/a Txt @ v = spf1 mx IP75.147.182.214ip6: fe80 :: 725a: fff: fe49: 3e02 ~ lahat default._bimi Txt N/a v = bimi1; l = https: //femmebabe.com/media/static/femmebabe.svg _dmarc Txt N/a v = dmarc1; P = wala sendonly._domainkey Txt N/aNgayon, kakailanganin naming magdagdag ng ilang patuloy na pagsasaayos para sa Postfix. Ang kailangan lang nating gawin ay siguraduhin na palitan namin ang pangalan ng domain, femmebabe.com, kasama ang pangalan ng domain na iyong ginagamit. Tingnan natin ang lahat ng mga file ng config nang paisa -isa, at i -install ang mga ito sa isang direktoryo na tinatawag na config sa aming proyekto, para sa pag -install sa OS.

nano config/etc_postfix_main.cf
Idagdag ang tekstong ito sa file

# Tingnan /usr/share/postfix/main.cf.dist para sa isang puna, mas kumpletong bersyon


# Debian Tukoy: Ang pagtukoy ng isang pangalan ng file ay magiging sanhi ng una
# linya ng file na iyon na gagamitin bilang pangalan.  Ang default na debian
# ay /etc /mailname.
# myorigin = /etc /mailname

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

# Appending .Domain ang trabaho ng MUA.
append_dot_mydomain = no

# Uncomment sa susunod na linya upang makabuo ng mga babala na "naantala na mail"
# pagkaantala_warning_time = 4h

readme_directory = no

# Tingnan ang http://www.postfix.org/compatibility_readme.html - default sa 3.6 on
# sariwang pag -install.
compatibility_level = 3.6



# Mga parameter ng 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

# Pag -configure ng 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
Susunod na config!

nano config/etc_postfix_master.cf
Idagdag ang mga linyang ito:

# 
# File ng Pag -configure ng Proseso ng Postfix Master.  Para sa mga detalye sa format
# ng file, tingnan ang Master (5) Manu -manong Pahina (utos: "Man 5 Master" o
# On-line: http://www.postfix.org/master.5.html).
# 
# Huwag kalimutan na isagawa ang "Postfix Reload" pagkatapos ng pag -edit ng file na ito.
# 
# ===================================================================================================== ========================
# Uri ng Serbisyo Pribadong Hindi CHROOT Wakeup MaxProc Command + Args
# (oo) (oo) (hindi) (hindi kailanman) (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
# Pumili ng isa: Paganahin ang pagsusumite para sa mga kliyente ng Loopback lamang, o para sa anumang kliyente.
# 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/pagsusumite
# -o smtpd_tls_security_level = encrypt
# -O smtpd_sasl_auth_enable = oo
# -O smtpd_tls_auth_only = oo
# -O smtpd_reject_unlisted_recipient = hindi
# -O SMTPD_CLIENT_RESTRICTIONS = $ MUA_CLIENT_RESTRICTIONS
# -O SMTPD_HELO_RESTRICTIONS = $ MUA_HELO_RESTRICTIONS
# -O SMTPD_SENDER_RESTRICTIONS = $ MUA_SENDER_RESTRICTIONS
# -O SMTPD_RECIPIENT_TRASTRICTIONS =
# -o smtpd_relay_restrictions = permit_sasl_authenticated, tanggihan
# -O MILTER_MACRO_DAEMON_NAME = nagmula
# Pumili ng isa: Paganahin ang mga SMTP para sa mga kliyente ng Loopback lamang, o para sa anumang kliyente.
# 127.0.0.1:SMTPS inet n - y - - smtpd
# smtps inet n - y - - smtpd
# -O syslog_name = postfix/smtps
# -O SMTPD_TLS_WRAPPERMODE = oo
# -O smtpd_sasl_auth_enable = oo
# -O smtpd_reject_unlisted_recipient = hindi
# -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 = permit_sasl_authenticated, tanggihan
# -O MILTER_MACRO_DAEMON_NAME = nagmula
# 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 OQMGR
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
# 
# ===================================================================================================== =================
# Mga interface sa non-postfix software. Siguraduhing suriin ang manu -manong
# mga pahina ng non-Postfix software upang malaman kung anong mga pagpipilian ang nais nito.
# 
# Marami sa mga sumusunod na serbisyo ang gumagamit ng paghahatid ng Postfix Pipe (8)
# ahente  Tingnan ang pahina ng Pipe (8) Babae para sa impormasyon tungkol sa $ {tatanggap}
# at iba pang mga pagpipilian sa sobre ng mensahe.
# ===================================================================================================== =================
# 
# Maildrop. Tingnan ang file ng postfix maildrop_readme para sa mga detalye.
# Tukuyin din sa main.cf: maildrop_destination_recipient_limit = 1
# 
maildrop  unix  -       n       n       -       -       pipe
  flags=DRXhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
# 
# ===================================================================================================== =================
# 
# Ang mga kamakailang bersyon ng Cyrus ay maaaring gumamit ng umiiral na "LMTP" master.cf entry.
# 
# Tukuyin sa Cyrus.conf:
# lmtp cmd = "lmtpd -a" makinig = "localhost: lmtp" proto = tcp4
# 
# Tukuyin sa main.cf isa o higit pa sa mga sumusunod:
# mailbox_transport = lmtp: inet: localhost
# Virtual_transport = lmtp: inet: localhost
# 
# ===================================================================================================== =================
# 
# Cyrus 2.1.5 (Amos Gouaux)
# Tukuyin din sa Main.cf: cyrus_destination_recipient_limit = 1
# 
# Cyrus Unix - n n - - pipe
# mga watawat = drx user = cyrus arg =/cyrus/bin/maghatid -e -r $ {sender} -m $ {extension} $ {user}
# 
# ===================================================================================================== =================
# Lumang halimbawa ng paghahatid sa pamamagitan ng Cyrus.
# 
# Old -cyrus unix - n n - - pipe
# mga watawat = r user = cyrus argv =/cyrus/bin/maghatid -e -m $ {extension} $ {user}
# 
# ===================================================================================================== =================
# 
# Tingnan ang postfix uucp_readme file para sa mga detalye ng pagsasaayos.
# 
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
# 
# Iba pang mga panlabas na pamamaraan ng paghahatid.
# 
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}
At ang pagsasaayos ng Opendkim. Kinikilala ng Opendkim ang mga server ng email na may mga susi ng domain upang mas ligtas sila. Kung wala ito, ang mail ay hindi naka -sign at maaaring hindi gawin ito sa isang inbox.

nano config/etc_default_opendkim
Idagdag ang mga linyang ito:

# Tandaan: Ito ay isang file ng pagsasaayos ng legacy. Hindi ito ginagamit ng Opendkim
# SISTEMD SERVICE. Mangyaring gamitin ang kaukulang mga parameter ng pagsasaayos sa
# /etc/opendkim.conf sa halip.
# 
# Dati, i -edit ng isa ang mga default na setting dito, at pagkatapos ay isagawa
# /lib/opendkim/opendkim.service.genererate upang makabuo ng mga file na override ng systemd sa
# /etc/systemd/system/opendkim.service.d/override.conf at
# /etc/tmpfiles.d/opendkim.conf. Habang posible pa rin ito, ngayon na
# Inirerekumenda upang ayusin ang mga setting nang direkta sa /etc/opendkim.conf.
# 
# Daemon_opts = ""
# Baguhin sa/var/spool/postfix/run/opendkim upang magamit ang isang unix socket na may
# Postfix sa isang chroot:
# Rundir =/var/spool/postfix/run/opendkim
RUNDIR=/run/opendkim
# 
# Uncomment upang tukuyin ang isang kahaliling socket
# Tandaan na ang pagtatakda nito ay lalampas ang anumang halaga ng socket sa opendkim.conf
# Default:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# Makinig sa lahat ng mga interface sa port 54321:
# Socket = inet: 54321
# Makinig sa loopback sa port 12345:
# Socket = inet: 12345@localhost
# Makinig ay 192.0.2.1 ay port 12345:
# Socket = inet: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=

nano config/etc_dovecot_conf.d_10-master.conf
Idagdag ang mga linyang ito:

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

# Default vsz (virtual memory size) limitasyon para sa mga proseso ng serbisyo. Ito ay higit sa lahat
# inilaan upang mahuli at patayin ang mga proseso na tumagas memorya bago sila kumain
# Lahat.
# Default_vsz_limit = 256m

# Ang gumagamit ng pag -login ay panloob na ginagamit ng mga proseso ng pag -login. Ito ang pinaka hindi mapagkakatiwalaan
# Gumagamit sa Dovecot System. Hindi ito dapat magkaroon ng access sa anumang bagay.
# default_login_user = dovenull

# Ang panloob na gumagamit ay ginagamit ng mga hindi nabuong proseso. Dapat itong hiwalay sa
# Gumagamit ang pag -login, upang ang mga proseso ng pag -login ay hindi makagambala sa iba pang mga proseso.
# default_internal_user = dovecot

service imap-login {
  inet_listener imap {
    # Port = 143
  }
  inet_listener imaps {
    # Port = 993
    # ssl = oo
  }

  # Bilang ng mga koneksyon upang hawakan bago simulan ang isang bagong proseso. Karaniwan
  # Ang tanging kapaki -pakinabang na mga halaga ay 0 (walang limitasyong) o 1. 1 ay mas ligtas, ngunit 0
  # ay mas mabilis. <doc/wiki/loginProcess.txt>
  # service_count = 1

  # Bilang ng mga proseso upang laging patuloy na maghintay para sa higit pang mga koneksyon.
  # Proseso_min_avail = 0

  # Kung nagtakda ka ng service_count = 0, marahil kailangan mong palaguin ito.
  # vsz_limit = $ default_vsz_limit
}

service pop3-login {
  inet_listener pop3 {
    # Port = 110
  }
  inet_listener pop3s {
    # Port = 995
    # ssl = oo
  }
}

service submission-login {
  inet_listener submission {
    # Port = 587
  }
}

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

  # Lumikha lamang ng Inet na nakikinig kung hindi mo magagamit ang UNIX socket
  # inet_lister lmtp {
    # Iwasang makita ang LMTP para sa buong internet
    # address =
    # port =
  # Hunos
}

service imap {
  # Karamihan sa memorya ay napupunta sa mga file ng MMAP (). Maaaring kailanganin mong dagdagan ito
  # Limitahan kung mayroon kang malaking mga mailbox.
  # vsz_limit = $ default_vsz_limit

  # Max. Bilang ng Mga Proseso ng IMAP (Koneksyon)
  # Proseso_limit = 1024
}

service pop3 {
  # Max. Bilang ng mga proseso ng POP3 (koneksyon)
  # proseso_limit = 1024
}

service submission {
  # Max. Bilang ng mga proseso ng pagsusumite ng SMTP (koneksyon)
  # proseso_limit = 1024
}

service auth {
  # AUTH_SOCKET_PATH POINTS sa socket ng UserDB na ito nang default. Karaniwan ito
  # Ginamit ng Dovecot-LDA, Doveadm, posibleng proseso ng IMAP, atbp.
  # Ang buong pahintulot sa socket na ito ay makakakuha ng isang listahan ng lahat ng mga username at
  # Kunin ang mga resulta ng mga lookup ng userdb ng lahat.
  # 
  # Pinapayagan ng default na 0666 mode ang sinuman na kumonekta sa socket, ngunit ang
  # Ang mga lookup ng userdb ay magtagumpay lamang kung ang UserDB ay magbabalik ng isang "uid" na patlang na
  # tumutugma sa UID ng proseso ng tumatawag. Gayundin kung ang caller's uid o gid ay tumutugma sa
  # socket's uid o gid ang lookup magtagumpay. Anumang iba pa ay nagiging sanhi ng isang pagkabigo.
  # 
  # Upang mabigyan ng buong pahintulot ang tumatawag upang hanapin ang lahat ng mga gumagamit, itakda ang mode sa
  # may iba pa kaysa sa 0666 at pinapayagan ng dovecot ang kernel na ipatupad ang
  # Pinapayagan ng mga pahintulot (hal. 0777 ang lahat ng buong pahintulot).
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}

service auth-worker {
  # Ang proseso ng manggagawa ng may -akda ay tatakbo bilang ugat bilang default, upang ma -access ito
  # /etc/anino. Kung hindi ito kinakailangan, dapat baguhin ang gumagamit
  # $ default_interal_user.
  # Gumagamit = ugat
}

service dict {
  # Kung ginagamit ang dict proxy, ang mga proseso ng mail ay dapat magkaroon ng access sa socket nito.
  # Halimbawa: mode = 0660, pangkat = vmail at pandaigdigang mail_access_groups = vmail
  unix_listener dict {
    # Mode = 0600
    # Gumagamit =
    # pangkat =
  }
}
Muli, siguraduhing palitan ang domain sa lahat ng mga file na ito, femmebabe.com, kasama ang domain na iyong napili. I -edit ang susunod na file, config ni Dovecot,

nano config/etc_dovecot_dovecot
At idagdag ang mga linyang ito

## File ng pagsasaayos ng OVECOT

# Kung nagmamadali ka, tingnan ang http://wiki2.dovecot.org/quickconfiguration

# Ang utos na "DoveConf -n" ay nagbibigay ng isang malinis na output ng mga nabago na setting. Gamitin ito
# Sa halip na kopyahin at pag -paste ng mga file kapag nag -post sa listahan ng mailing dovecot.

# '# 'Character at lahat ng bagay pagkatapos itong ituring bilang mga komento. Sobrang puwang
# At ang mga tab ay hindi pinansin. Kung nais mong gamitin ang alinman sa mga ito nang malinaw, ilagay ang
# value inside quotes, eg.: key = "# char at trailing whitespace "

# Karamihan (ngunit hindi lahat) mga setting ay maaaring ma -overridden ng iba't ibang mga protocol at/o
# Pinagmulan/patutunguhang IP sa pamamagitan ng paglalagay ng mga setting sa loob ng mga seksyon, halimbawa:
# Protocol IMAP {}, Lokal na 127.0.0.1 {}, Remote 10.0.0.0/8 {}

# Ang mga halaga ng default ay ipinapakita para sa bawat setting, hindi kinakailangan na hindi pangkomunikasyon
# yun. Ito ang mga pagbubukod sa ito bagaman: walang mga seksyon (hal. Namespace {})
# o mga setting ng plugin ay idinagdag bilang default, nakalista lamang sila bilang mga halimbawa.
# Ang mga landas ay mga halimbawa din na may tunay na mga default na batay sa pag -configure
# mga pagpipilian. Ang mga landas na nakalista dito ay para sa pag -configure --prefix =/usr
# --Sconfdir =/etc--localstatedir =/var

# Paganahin ang mga naka -install na protocol
!include_try /usr/share/dovecot/protocols.d/*.protocol

# Isang listahan ng comma na pinaghiwalay ng mga IP o host kung saan makikinig para sa mga koneksyon.
# "*" Nakikinig sa lahat ng mga interface ng IPv4, "::" nakikinig sa lahat ng mga interface ng IPv6.
# Kung nais mong tukuyin ang mga port na hindi default o anumang mas kumplikado,
# I -edit ang Conf.D/Master.conf.
# Makinig = *, ::

# Base Directory kung saan mag -iimbak ng data ng runtime.
# Base_dir =/var/run/dovecot/

# Pangalan ng pagkakataong ito. Sa multi-instance setup doveadm at iba pang mga utos
# maaaring gumamit -i <pstant_name> upang piliin kung aling halimbawa ang ginagamit (isang alternatibo
# TO -C <Config_Path>). Ang pangalan ng halimbawa ay idinagdag din sa mga proseso ng dovecot
# sa PS output.
# halimbawa_name = dovecot

# Pagbati ng mensahe para sa mga kliyente.
# login_greeting = Handa ng DoveCot.

# Listahan ng Hiwalay na Listahan ng Mga Pinagkakatiwalaang Mga Saklaw ng Network. Mga koneksyon mula sa mga ito
# Pinapayagan ang mga IP na i -override ang kanilang mga IP address at port (para sa pag -log at
# para sa mga tseke ng pagpapatunay). Huwag paganahin ang_plaintext_auth ay hindi rin pinansin
# Ang mga network na ito. Karaniwan mong tukuyin ang iyong mga server ng IMAP proxy dito.
# login_trusted_networks =

# Listahan ng Paghiwalay ng Space ng Mga Suriin ng Pag -access sa Pag -login (hal. TCPWRAP)
# login_access_sockets =

# Na may proxy_maybe = oo kung ang patutunguhang patutunguhan ay tumutugma sa alinman sa mga IP na ito, huwag gawin
# proxying. Hindi ito kinakailangan nang normal, ngunit maaaring maging kapaki -pakinabang kung ang patutunguhan
# Ang IP ay hal. Isang IP ng Load Balancer.
# auth_proxy_self =

# Magpakita ng higit pang mga pamagat ng proseso ng pandiwa (sa PS). Kasalukuyang nagpapakita ng pangalan ng gumagamit at
# IP address. Kapaki -pakinabang para makita kung sino ang aktwal na gumagamit ng mga proseso ng IMAP
# (hal. Ibinahaging mga mailbox o kung ang parehong UID ay ginagamit para sa maraming mga account).
# verbose_proctitle = no

# Dapat bang papatayin ang lahat ng mga proseso kapag ang proseso ng master ng dovecot ay bumagsak.
# Ang pagtatakda nito sa "hindi" ay nangangahulugang ang Dovecot ay maaaring ma -upgrade nang wala
# pagpilit sa umiiral na mga koneksyon sa kliyente upang isara (kahit na maaari din iyon
# Isang problema kung ang pag -upgrade ay hal. Dahil sa isang pag -aayos ng seguridad).
# shutdown_clients = oo

# Kung non-zero, patakbuhin ang mga utos ng mail sa pamamagitan ng maraming mga koneksyon sa doveadm server,
# sa halip na patakbuhin ang mga ito nang direkta sa parehong proseso.
# doveadm_worker_count = 0
# Unix Socket o Host: Port na ginamit para sa pagkonekta sa Doveadm Server
# doveadm_socket_path = doveadm-server

# Listahan ng Hiwalay na Space ng Mga variable ng Kapaligiran na Napapanatili sa Dovecot
# Startup at ipinasa sa lahat ng mga proseso ng bata nito. Maaari ka ring magbigay
# key = mga pares ng halaga upang palaging magtakda ng mga tukoy na setting.
# Import_environment = tz

## 
## Mga setting ng server ng diksyunaryo
## 

# Ang diksyunaryo ay maaaring magamit upang mag -imbak ng mga listahan ng key = halaga. Ginagamit ito ng maraming
# Plugins. Ang diksyunaryo ay maaaring ma -access nang direkta o kahit na a
# server ng diksyunaryo. Ang mga sumusunod na dict block ay mga pangalan ng diksyunaryo sa mga URI
# Kapag ginamit ang server. Maaari itong mai -refer gamit ang mga URI sa format
# "Proxy :: <name>".

dict {
  # quota = mysql: /andc/dovecot/dovecot-dic-sql.conf.ext
}

# Karamihan sa aktwal na pagsasaayos ay makakakuha ng kasama sa ibaba. Ang mga filenames ay
# Una na pinagsunod -sunod ng kanilang halaga ng ASCII at naka -parse sa pagkakasunud -sunod na iyon. Ang 00-prefix
# Sa mga filenames ay inilaan upang mas madaling maunawaan ang pag -order.
!include conf.d/*.conf

# Ang isang config file ay maaari ring subukan na isama nang hindi nagbibigay ng isang error kung
# Hindi ito natagpuan:
!include_try local.conf

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

protocols = imap pop3

# Pinapayagan ang DoveCot na makinig sa lahat ng mga koneksyon sa pag -input (IPv4 / IPv6)

listen = *, ::
Magdagdag ng isang password para sa gumagamit ng DoveCot:

nano config/etc_dovecot_passwd
Ang unang bahagi ng file, bago ang colon, ay ang username. Ang huling bahagi, "Ang iyongPassword", ay nagpapahiwatig ng password na nais mong ibigay sa iyong mail server.

team:{plain}yourpassword
Susunod, ang Opendkim config

nano config/etc_opendkim.conf
At idagdag ang mga linyang ito:

# Ito ay isang pangunahing pagsasaayos para sa pag -sign at pag -verify. Madali itong maging
# Inangkop upang umangkop sa isang pangunahing pag -install. Tingnan ang Opendkim.conf (5) at
# /usr/share/doc/opendkim/examples/opendkim.conf.sample para kumpleto
# Dokumentasyon ng magagamit na mga parameter ng pagsasaayos.

Syslog			yes
SyslogSuccess		yes
# Logwhy no

# Karaniwang mga parameter ng pag -sign at pag -verify. Sa Debian, ang "mula" header ay
# oversigned, sapagkat madalas na ang key ng pagkakakilanlan na ginagamit ng mga sistema ng reputasyon
# at sa gayon medyo sensitibo sa seguridad.
Canonicalization	relaxed/simple
Mode			s
SubDomains		no
OversignHeaders		From

# Pag -sign domain, selector, at key (kinakailangan). Halimbawa, magsagawa ng pag -sign
# Para sa domain "halimbawa.com" kasama ang selector "2020" (2020._domainkey.example.com),
# Gamit ang pribadong key na nakaimbak sa /etc/dkimkeys/example.private. Mas butil
# Ang mga pagpipilian sa pag -setup ay matatagpuan sa /usr/share/doc/opendkim/readme.opendkim.
# Halimbawa ng Domain.com
# Selector 2020
# Keyfile /etc/dkimkeys/example.private

# Sa Debian, ang Opendkim ay tumatakbo bilang gumagamit na "Opendkim". Kinakailangan ang isang ugmask ng 007 kung kailan
# Gamit ang isang lokal na socket na may MTA na nag-access sa socket bilang isang hindi privile
# Gumagamit (halimbawa, Postfix). Maaaring kailanganin mong magdagdag ng "postfix" ng gumagamit sa pangkat
# "Opendkim" sa kasong iyon.
UserID			opendkim
UMask			007

# Socket para sa koneksyon sa MTA (kinakailangan). Kung ang MTA ay nasa loob ng isang kulungan ng chroot,
# Dapat tiyakin na maa -access ang socket. Sa Debian, ang Postfix ay tumatakbo
# Isang chroot in/var/spool/postfix, samakatuwid ang isang socket ng UNIX ay kailangang maging
# Na -configure tulad ng ipinapakita sa huling linya sa ibaba.
# Socket lokal: /run/opendkim/opendkim.sock
# Socket Inet: 8891@localhost
# Socket Inet: 8891
Socket			local:/var/spool/postfix/opendkim/opendkim.sock

PidFile			/run/opendkim/opendkim.pid

# Ang mga host kung saan mag -sign sa halip na i -verify, ang default ay 127.0.0.1. Tingnan ang
# Ang seksyon ng operasyon ng Opendkim (8) para sa karagdagang impormasyon.
# InternalHost 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12

# Ang tiwala na anchor ay nagbibigay -daan sa DNSSEC. Sa Debian, ibinigay ang file ng tiwala ng anchor
# sa pamamagitan ng package dns-root-data.
TrustAnchorFile		/usr/share/dns/root.key
# Nameservers 127.0.0.1

# Mga domain ng mapa mula sa mga address hanggang sa mga susi na ginamit upang mag -sign ng mga mensahe
KeyTable           refile:/etc/opendkim/key.table
SigningTable       refile:/etc/opendkim/signing.table

# Isang hanay ng mga panloob na host na ang mail ay dapat na pirmahan
InternalHosts       /etc/opendkim/trusted.hosts

nano config/etc_default_opendkim
At idagdag ang mga linyang ito

# Tandaan: Ito ay isang file ng pagsasaayos ng legacy. Hindi ito ginagamit ng Opendkim
# SISTEMD SERVICE. Mangyaring gamitin ang kaukulang mga parameter ng pagsasaayos sa
# /etc/opendkim.conf sa halip.
# 
# Dati, i -edit ng isa ang mga default na setting dito, at pagkatapos ay isagawa
# /lib/opendkim/opendkim.service.genererate upang makabuo ng mga file na override ng systemd sa
# /etc/systemd/system/opendkim.service.d/override.conf at
# /etc/tmpfiles.d/opendkim.conf. Habang posible pa rin ito, ngayon na
# Inirerekumenda upang ayusin ang mga setting nang direkta sa /etc/opendkim.conf.
# 
# Daemon_opts = ""
# Baguhin sa/var/spool/postfix/run/opendkim upang magamit ang isang unix socket na may
# Postfix sa isang chroot:
# Rundir =/was/spool/postfix/run/opendkim
RUNDIR=/run/opendkim
# 
# Uncomment upang tukuyin ang isang kahaliling socket
# Tandaan na ang pagtatakda nito ay lalampas ang anumang halaga ng socket sa opendkim.conf
# Default:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# Makinig sa lahat ng mga interface sa port 54321:
# Socket = inet: 54321
# Makinig sa loopback sa port 12345:
# Socket = inet: 12345@localhost
# Makinig ay 192.0.2.1 ay port 12345:
# Socket = inet: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=
Kapag handa na kaming i -set up ang aming Postfix Server, tatakbo kami sa ibaba ng code, na may naaangkop na pangalan ng domain na naka -embed. Magsimula sa pamamagitan ng paglikha ng isang script

touch scripts/postfixsetup
sudo chmod a+x scripts/postfixsetup
nano scripts/postfixsetup
Ngayon, sa Nano, ang text editor, i -edit ang file na ito upang kasama nito ang iyong domain name sa halip na femmebabe.com.

# !
# Setup 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}'
Ngayon, patakbuhin ang nakumpletong script upang i -configure ang Postfix, Opendkim at Dovecot.

./scripts/postfixsetup
Kapag tumakbo ang script na ito, kopyahin ang huling linya na ito ay nag -print at i -paste ito sa iyong pagsasaayos ng DNS bilang halaga para sa sendonly._domainkey. Ito ang Opendkim key na ginamit upang makilala ang iyong domain kapag nagpapadala ng ligtas na mail. Galing! Sa loob ng ilang araw, dapat mong magpadala ng mail mula sa server na ibinigay ang lahat ay na -configure nang tama. Kung na -configure mo lamang ang DNS para sa iyong mail server, dapat itong tumagal ng mas mababa sa 72 oras para ma -update ang mga talaan. Karaniwan itong mas mabilis. Maaari mong suriin kung ang iyong server ay nagtatrabaho sa pamamagitan ng paggamit ng utos na ito, ibinigay ang iyong email:

echo “test” | mail -s “Test Email” youremail@gmail.com
Kung ang lahat ay lilitaw na gumagana nang tama, dapat kang magpadala ng email sa iyong server. Kung hindi ito gumagana, subukang tingnan ang mga log upang makita kung ano ang maaaring mangyari.

tail –lines 150 /var/log/mail.log
Mag -aalok ito ng impormasyon ng pandiwa tungkol sa mail na ipinapadala ng server at kung ito ay gumagana nang maayos. Dapat mong makita ang email sa iyong inbox din, kung wala ito, suriin ang iyong folder ng spam. Kailangan mo ring i -configure ang iyong mga setting sa iyong mga setting.py upang ang iyong email server ay maaaring makipag -usap sa iyong Django app, ang proyekto. Idagdag o palitan ang mga linyang ito sa iyong mga setting

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)
Pansinin na gumagamit kami ng isang config file upang makuha ang password. I -load natin ang file na ito sa mga setting tulad ng gayon, sa pinakadulo simula ng file.:

import os
import json

# Buksan at i -load ang config
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
Lumikha tayo ng file na ito at magdagdag ng isang lihim na susi dito, pati na rin ang password ng mail. Upang makabuo ng isang lihim na susi, gamitin ang utos na ito, na may anumang haba na gusto mo sa dulo:

openssl rand -base64 64
Ngayon, kopyahin ang teksto na nabuo ng OpenSSL at i -edit /etc/config.json

sudo nano /etc/config.json
Idagdag ang mga sumusunod na linya sa iyong file, kasama ang susi na binuo ng OpenSSL bilang lihim na susi.

{
	"SECRET_KEY": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX-generated-using-openssl)",
	"EMAIL_HOST_PASSWORD": "yourpassword"
}
Ang format ng JSON ay simple at madaling gamitin, maaari naming ipahayag ang iba pang mga susi na nais naming gamitin sa aming proyekto sa ganitong paraan, at panatilihin silang hiwalay sa aming direktoryo ng proyekto upang ang ibang mga gumagamit ay hindi maaaring sumulat sa kanila at sa gayon hindi sila mabasa mula sa aming direktoryo ng proyekto lamang. Inirerekomenda ang kasanayan para sa mga susi ng API, kung saan gagamitin namin ang higit sa iilan dito. Gusto mo ring i -back up ang iyong proyekto upang matiyak na ang lahat ay nai -save at magagawa mong mabawi ang iyong trabaho sa ibang pagkakataon kahit na hindi mo na nais na magrenta ng isang server.

sudo backup
Ngayon, subukang magpadala ng isang email ng HTML mula sa web server, na ibinigay ang pagpapadala ng isa mula sa linya ng utos ay gumagana. Query ang iyong halimbawa ng gumagamit sa shell, at magpadala ng isang email ng HTML sa gumagamit na iyon sa pamamagitan ng Django. Baguhin ang aking pangalan sa code, Charlotte, sa iyong username.

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()
Kung ang unang utos ay hindi gumana, siguraduhing gamitin

source venv/bin/activate
Sa kondisyon na ang lahat ay naka -set up nang tama, makakakuha ka na ngayon ng isang malugod na email sa iyong mailbox na ipinadala ng iyong web app. Magandang trabaho! Malayo ka na. Nais kong idagdag, kung ikaw ay kailanman nakikipaglaban sa anumang mga pagkakamali habang nagtatrabaho sa isang proyekto na tulad nito, huwag mag -atubiling maghanap ng mga sagot at humingi ng tulong. Ang Google, bukod sa iba pang mga search engine, ay mahusay na mapagkukunan upang maghanap ng tulong sa programming. Maghanap lamang ng error na nakukuha mo, at makikita mo kung paano malulutas ng ibang tao ang problema. Gayundin, malugod kang makipag -ugnay sa akin, ang iyong mga tagapagturo (mga guro, propesor, tutor), anumang mga kapantay sa Internet na magagamit para sa tulong sa programming, o kumunsulta muli sa aklat na ito o iba pang mga mapagkukunan upang makahanap ng mga solusyon sa mga isyu na iyong nararanasan. Naiintindihan ko na ito ay hindi madali, ngunit kahit na nabasa mo na ito at hindi nagsusulat ng anumang code, marami kang natututo tungkol sa pagbuo ng isang web app mula sa simula. Pat ang iyong sarili sa likod, mahusay ang iyong ginagawatrabaho. Salamat sa paglaan ng oras upang mabasa ang Gabay sa Ikatlong Edisyon ng Web Development. Sa mga hinaharap na edisyon, isasama ko ang higit pa sa mga mahahalagang halimbawa na tinalakay sa simula ng dokumento at masisid ang mas malalim sa mundo ng software at pag -unlad ng hardware. Manatiling nakatutok para sa darating, at inaasahan kong turuan ka kung paano bumuo ng hindi kapani -paniwala na software. Magkita tayo sa susunod






Malapit
Pahina 1
Tumalon
Tingnan ang buong artikulo
Magpatuloy sa pagbabasa

Bumili | Bumili gamit ang crypto



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


(I-click o i-tap para mag-download ng larawan)
Propesyonal na entertainment, mga larawan, video, audio, livestreaming at kaswal na gameplay, pati na rin ang pag-scan ng ID, web development at mga serbisyo ng surrogacy.

Mag-iwan sa akin ng tip sa Bitcoin gamit ang address na ito: 3KhDWoSve2N627RiW8grj6XrsoPT7d6qyE

© Glam Girl X 2025

Mga Tuntunin ng Serbisyo