├── templates
├── assets
│ ├── img
│ │ ├── logo.png
│ │ ├── favicon.ico
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── mstile-150x150.png
│ │ ├── apple-touch-icon.png
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── browserconfig.xml
│ │ └── site.webmanifest
│ ├── js
│ │ └── script.min.js
│ └── css
│ │ ├── styles.min.css
│ │ └── easymde.min.css
├── elements
│ └── post_card.html
├── privacy.html
├── errcode.html
├── unsubscribe.html
├── index.html
├── error.html
├── success.html
├── emails
│ ├── newsletter.html
│ ├── verification.html
│ ├── unsubscribe.html
│ └── newsletterv2.html
├── setup.html
├── dashboard.html
├── editor.html
├── subscribers.html
└── settings.html
├── requirements.txt
├── tools
├── configuration.py
├── htmlgen.py
└── mailer.py
├── SECURITY.md
├── .github
├── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
└── workflows
│ └── codeql-analysis.yml
├── .gitignore
├── README.md
├── main.py
└── LICENSE.md
/templates/assets/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/berrysauce/microletter/HEAD/templates/assets/img/logo.png
--------------------------------------------------------------------------------
/templates/assets/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/berrysauce/microletter/HEAD/templates/assets/img/favicon.ico
--------------------------------------------------------------------------------
/templates/assets/img/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/berrysauce/microletter/HEAD/templates/assets/img/favicon-16x16.png
--------------------------------------------------------------------------------
/templates/assets/img/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/berrysauce/microletter/HEAD/templates/assets/img/favicon-32x32.png
--------------------------------------------------------------------------------
/templates/assets/img/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/berrysauce/microletter/HEAD/templates/assets/img/mstile-150x150.png
--------------------------------------------------------------------------------
/templates/assets/img/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/berrysauce/microletter/HEAD/templates/assets/img/apple-touch-icon.png
--------------------------------------------------------------------------------
/templates/assets/img/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/berrysauce/microletter/HEAD/templates/assets/img/android-chrome-192x192.png
--------------------------------------------------------------------------------
/templates/assets/img/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/berrysauce/microletter/HEAD/templates/assets/img/android-chrome-512x512.png
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | fastapi
2 | uvicorn
3 | markdown
4 | beautifulsoup4
5 | jinja2
6 | deta
7 | python-dotenv
8 | aiofiles
9 | python-multipart
10 | lxml
--------------------------------------------------------------------------------
/templates/assets/js/script.min.js:
--------------------------------------------------------------------------------
1 | document.addEventListener("DOMContentLoaded",(function(){[].slice.call(document.querySelectorAll("[data-bss-tooltip]")).map((function(t){return new bootstrap.Tooltip(t)}))}),!1);
--------------------------------------------------------------------------------
/tools/configuration.py:
--------------------------------------------------------------------------------
1 | from deta import Deta
2 | from dotenv import load_dotenv
3 | import os
4 |
5 | load_dotenv()
6 | deta = Deta(os.getenv("DETA_TOKEN"))
7 | config = deta.Base("microletter-config")
8 |
9 | def get(value):
10 | return config.fetch(None).items[0][value]
--------------------------------------------------------------------------------
/templates/assets/img/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
{{ excerpt }}
30 | {{ error_description }} - (the server literally threw an error)
31 |
32 |
33 |
34 |
You have no posts
""" 17 | else: 18 | entries.sort(key = lambda x:x["date"]) 19 | entries = entries[::-1] 20 | posts_html = """""" 21 | with open("templates/elements/post_card.html", "r") as f: 22 | posts_html_template = jinja2.Template(f.read()) 23 | for entry in entries: 24 | data = { 25 | "title": entry["title"], 26 | "date": entry["date"], 27 | "excerpt": entry["excerpt"], 28 | "delete_link": "/dashboard/home/delete/{0}".format(entry["key"]) 29 | } 30 | posts_html = posts_html + posts_html_template.render(data) 31 | return posts_html 32 | 33 | def subscribertable(): 34 | entries = subscribers.fetch({"verified": True}).items 35 | month = str(datetime.now().strftime("%B %Y")) 36 | total_subscribers = len(entries) 37 | monthly_subscribers = 0 38 | table_html = """""" 39 | 40 | if len(entries) != 0: 41 | entries.sort(key = lambda x:x["subscribed_on"]) 42 | entries = entries[::-1] 43 | 44 | for entry in entries: 45 | if month in entry["subscribed_on"]: 46 | monthly_subscribers += 1 47 | delete_link = "/dashboard/subscribers/delete/{0}".format(entry["key"]) 48 | table_html = table_html + """ 49 |
47 | {{ description }}
48 |
49 |
50 |
51 |
48 | {{ description }}
49 |
50 |
51 |
52 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
78 | {{ newsletter_title }}79 | 80 | |
81 |
82 |
88 | {{ post_title }}89 |{{ post_date }} 90 |
91 | {% autoescape false %}
92 | {{ post_content }}
93 | {% endautoescape %}
94 |
95 | |
96 |
97 |
| 103 | 104 | 105 | | 106 | 107 |
75 | Verify your Email76 | 77 | |
78 |
79 |
|
85 |
86 | Please verify your Email to subscribe to {{ newsletter_title }}. If you don't verify your Email, you won't be subscribed. |
95 |
96 |
| 102 | 103 | 104 | | 105 | 106 |
75 | Confirm that you want to Unsubscribe76 | 77 | |
78 |
79 |
|
85 |
86 | Please verify that you want to unsubscribe from {{ newsletter_title }}. If you don't verify this, we won't remove your email from our list. |
95 |
96 |
| 102 | 103 | 104 | | 105 | 106 |

Before you can start using your own installation of microletter, you need to complete the initial setup.
30 |All of your newsletter posts can be found here.
130 | {% autoescape false %} {{ posts }} {% endautoescape %} 131 |Here are your current newsletter subscribers.
130 |{{ total_subscribers }}
{{ monthly_subscribers }}
| Subscribed on | 155 |156 | |
|---|
467 |
|
521 |