New Membership Page and other changes #4

Merged
kumi merged 29 commits from membership-page into main 2024-05-30 10:15:10 +00:00
33 changed files with 860 additions and 421 deletions

View file

@ -24,3 +24,8 @@ The website will be available at `http://localhost:9810`.
This project is licensed under the MIT License - see the [LICENSE](LICENSE) This project is licensed under the MIT License - see the [LICENSE](LICENSE)
file for details. file for details.
## Attribution
This website is built using the [Bootstrap](https://getbootstrap.com) framework
and [Phosphor Icons](https://phosphoricons.com).

View file

@ -85,6 +85,48 @@ h5 {
margin-top: 10px; margin-top: 10px;
} }
.currency-col {
width: 200px;
white-space: nowrap;
text-align: right;
}
.table-transparency td:not(:first-child) {
text-align: right;
}
.section {
padding: 20px 0;
border-bottom: 1px solid #e0e0e0;
}
.alert-warning {
background-color: #fff3cd;
border-color: #ffeeba;
color: #856404;
padding: 15px;
margin-bottom: 20px;
border-radius: 4px;
}
.alert-warning .alert-link {
color: #856404;
font-weight: bold;
text-decoration: underline;
}
.alert-warning .alert-link:hover {
color: #604c2e;
}
.bs-icon.bs-icon-primary svg {
fill: var(--bs-primary-bg-subtle);
}
.bs-icon.bs-icon-lg svg {
fill: var(--bs-primary)
}
/* Responsive Styles */ /* Responsive Styles */
@media (max-width: 768px) { @media (max-width: 768px) {
.navbar .container { .navbar .container {

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M128,96H232a8,8,0,0,1,0,16H128a8,8,0,0,1,0-16Zm104,32H128a8,8,0,0,0,0,16H232a8,8,0,0,0,0-16Zm0,32H80a8,8,0,0,0,0,16H232a8,8,0,0,0,0-16Zm0,32H80a8,8,0,0,0,0,16H232a8,8,0,0,0,0-16ZM96,144a8,8,0,0,0,0-16H88V64h32v8a8,8,0,0,0,16,0V56a8,8,0,0,0-8-8H32a8,8,0,0,0-8,8V72a8,8,0,0,0,16,0V64H72v64H64a8,8,0,0,0,0,16Z"></path></svg>

After

Width:  |  Height:  |  Size: 430 B

1
assets/dist/icons/calendar.svg vendored Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M208,32H184V24a8,8,0,0,0-16,0v8H88V24a8,8,0,0,0-16,0v8H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM72,48v8a8,8,0,0,0,16,0V48h80v8a8,8,0,0,0,16,0V48h24V80H48V48ZM208,208H48V96H208V208Zm-96-88v64a8,8,0,0,1-16,0V132.94l-4.42,2.22a8,8,0,0,1-7.16-14.32l16-8A8,8,0,0,1,112,120Zm59.16,30.45L152,176h16a8,8,0,0,1,0,16H136a8,8,0,0,1-6.4-12.8l28.78-38.37A8,8,0,1,0,145.07,132a8,8,0,1,1-13.85-8A24,24,0,0,1,176,136,23.76,23.76,0,0,1,171.16,150.45Z"></path></svg>

After

Width:  |  Height:  |  Size: 604 B

1
assets/dist/icons/chats.svg vendored Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M216,80H184V48a16,16,0,0,0-16-16H40A16,16,0,0,0,24,48V176a8,8,0,0,0,13,6.22L72,154V184a16,16,0,0,0,16,16h93.59L219,230.22a8,8,0,0,0,5,1.78,8,8,0,0,0,8-8V96A16,16,0,0,0,216,80ZM66.55,137.78,40,159.25V48H168v88H71.58A8,8,0,0,0,66.55,137.78ZM216,207.25l-26.55-21.47a8,8,0,0,0-5-1.78H88V152h80a16,16,0,0,0,16-16V96h32Z"></path></svg>

After

Width:  |  Height:  |  Size: 438 B

1
assets/dist/icons/coffee.svg vendored Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M80,56V24a8,8,0,0,1,16,0V56a8,8,0,0,1-16,0Zm40,8a8,8,0,0,0,8-8V24a8,8,0,0,0-16,0V56A8,8,0,0,0,120,64Zm32,0a8,8,0,0,0,8-8V24a8,8,0,0,0-16,0V56A8,8,0,0,0,152,64Zm96,56v8a40,40,0,0,1-37.51,39.91,96.59,96.59,0,0,1-27,40.09H208a8,8,0,0,1,0,16H32a8,8,0,0,1,0-16H56.54A96.3,96.3,0,0,1,24,136V88a8,8,0,0,1,8-8H208A40,40,0,0,1,248,120ZM200,96H40v40a80.27,80.27,0,0,0,45.12,72h69.76A80.27,80.27,0,0,0,200,136Zm32,24a24,24,0,0,0-16-22.62V136a95.78,95.78,0,0,1-1.2,15A24,24,0,0,0,232,128Z"></path></svg>

After

Width:  |  Height:  |  Size: 600 B

1
assets/dist/icons/database.svg vendored Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M128,24C74.17,24,32,48.6,32,80v96c0,31.4,42.17,56,96,56s96-24.6,96-56V80C224,48.6,181.83,24,128,24Zm80,104c0,9.62-7.88,19.43-21.61,26.92C170.93,163.35,150.19,168,128,168s-42.93-4.65-58.39-13.08C55.88,147.43,48,137.62,48,128V111.36c17.06,15,46.23,24.64,80,24.64s62.94-9.68,80-24.64ZM69.61,53.08C85.07,44.65,105.81,40,128,40s42.93,4.65,58.39,13.08C200.12,60.57,208,70.38,208,80s-7.88,19.43-21.61,26.92C170.93,115.35,150.19,120,128,120s-42.93-4.65-58.39-13.08C55.88,99.43,48,89.62,48,80S55.88,60.57,69.61,53.08ZM186.39,202.92C170.93,211.35,150.19,216,128,216s-42.93-4.65-58.39-13.08C55.88,195.43,48,185.62,48,176V159.36c17.06,15,46.23,24.64,80,24.64s62.94-9.68,80-24.64V176C208,185.62,200.12,195.43,186.39,202.92Z"></path></svg>

After

Width:  |  Height:  |  Size: 834 B

1
assets/dist/icons/envelope.svg vendored Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M224,48H32a8,8,0,0,0-8,8V192a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A8,8,0,0,0,224,48Zm-96,85.15L52.57,64H203.43ZM98.71,128,40,181.81V74.19Zm11.84,10.85,12,11.05a8,8,0,0,0,10.82,0l12-11.05,58,53.15H52.57ZM157.29,128,216,74.18V181.82Z"></path></svg>

After

Width:  |  Height:  |  Size: 360 B

1
assets/dist/icons/git-branch.svg vendored Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M232,64a32,32,0,1,0-40,31v17a8,8,0,0,1-8,8H96a23.84,23.84,0,0,0-8,1.38V95a32,32,0,1,0-16,0v66a32,32,0,1,0,16,0V144a8,8,0,0,1,8-8h88a24,24,0,0,0,24-24V95A32.06,32.06,0,0,0,232,64ZM64,64A16,16,0,1,1,80,80,16,16,0,0,1,64,64ZM96,192a16,16,0,1,1-16-16A16,16,0,0,1,96,192ZM200,80a16,16,0,1,1,16-16A16,16,0,0,1,200,80Z"></path></svg>

After

Width:  |  Height:  |  Size: 435 B

1
assets/dist/icons/images.svg vendored Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M216,40H72A16,16,0,0,0,56,56V72H40A16,16,0,0,0,24,88V200a16,16,0,0,0,16,16H184a16,16,0,0,0,16-16V184h16a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40ZM72,56H216v62.75l-10.07-10.06a16,16,0,0,0-22.63,0l-20,20-44-44a16,16,0,0,0-22.62,0L72,109.37ZM184,200H40V88H56v80a16,16,0,0,0,16,16H184Zm32-32H72V132l36-36,49.66,49.66a8,8,0,0,0,11.31,0L194.63,120,216,141.38V168ZM160,84a12,12,0,1,1,12,12A12,12,0,0,1,160,84Z"></path></svg>

After

Width:  |  Height:  |  Size: 525 B

1
assets/dist/icons/leaf.svg vendored Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M223.45,40.07a8,8,0,0,0-7.52-7.52C139.8,28.08,78.82,51,52.82,94a87.09,87.09,0,0,0-12.76,49c.57,15.92,5.21,32,13.79,47.85l-19.51,19.5a8,8,0,0,0,11.32,11.32l19.5-19.51C81,210.73,97.09,215.37,113,215.94q1.67.06,3.33.06A86.93,86.93,0,0,0,162,203.18C205,177.18,227.93,116.21,223.45,40.07ZM153.75,189.5c-22.75,13.78-49.68,14-76.71.77l88.63-88.62a8,8,0,0,0-11.32-11.32L65.73,179c-13.19-27-13-54,.77-76.71,22.09-36.47,74.6-56.44,141.31-54.06C210.2,114.89,190.22,167.41,153.75,189.5Z"></path></svg>

After

Width:  |  Height:  |  Size: 598 B

1
assets/dist/icons/lightbulb.svg vendored Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M176,232a8,8,0,0,1-8,8H88a8,8,0,0,1,0-16h80A8,8,0,0,1,176,232Zm40-128a87.55,87.55,0,0,1-33.64,69.21A16.24,16.24,0,0,0,176,186v6a16,16,0,0,1-16,16H96a16,16,0,0,1-16-16v-6a16,16,0,0,0-6.23-12.66A87.59,87.59,0,0,1,40,104.49C39.74,56.83,78.26,17.14,125.88,16A88,88,0,0,1,216,104Zm-16,0a72,72,0,0,0-73.74-72c-39,.92-70.47,33.39-70.26,72.39a71.65,71.65,0,0,0,27.64,56.3A32,32,0,0,1,96,186v6h64v-6a32.15,32.15,0,0,1,12.47-25.35A71.65,71.65,0,0,0,200,104Zm-16.11-9.34a57.6,57.6,0,0,0-46.56-46.55,8,8,0,0,0-2.66,15.78c16.57,2.79,30.63,16.85,33.44,33.45A8,8,0,0,0,176,104a9,9,0,0,0,1.35-.11A8,8,0,0,0,183.89,94.66Z"></path></svg>

After

Width:  |  Height:  |  Size: 728 B

1
assets/dist/icons/link.svg vendored Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M240,88.23a54.43,54.43,0,0,1-16,37L189.25,160a54.27,54.27,0,0,1-38.63,16h-.05A54.63,54.63,0,0,1,96,119.84a8,8,0,0,1,16,.45A38.62,38.62,0,0,0,150.58,160h0a38.39,38.39,0,0,0,27.31-11.31l34.75-34.75a38.63,38.63,0,0,0-54.63-54.63l-11,11A8,8,0,0,1,135.7,59l11-11A54.65,54.65,0,0,1,224,48,54.86,54.86,0,0,1,240,88.23ZM109,185.66l-11,11A38.41,38.41,0,0,1,70.6,208h0a38.63,38.63,0,0,1-27.29-65.94L78,107.31A38.63,38.63,0,0,1,144,135.71a8,8,0,0,0,16,.45A54.86,54.86,0,0,0,144,96a54.65,54.65,0,0,0-77.27,0L32,130.75A54.62,54.62,0,0,0,70.56,224h0a54.28,54.28,0,0,0,38.64-16l11-11A8,8,0,0,0,109,185.66Z"></path></svg>

After

Width:  |  Height:  |  Size: 714 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M229.66,218.34l-50.07-50.06a88.11,88.11,0,1,0-11.31,11.31l50.06,50.07a8,8,0,0,0,11.32-11.32ZM40,112a72,72,0,1,1,72,72A72.08,72.08,0,0,1,40,112Z"></path></svg>

After

Width:  |  Height:  |  Size: 267 B

1
assets/dist/icons/markdown-logo.svg vendored Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M232,48H24A16,16,0,0,0,8,64V192a16,16,0,0,0,16,16H232a16,16,0,0,0,16-16V64A16,16,0,0,0,232,48Zm0,144H24V64H232V192ZM128,104v48a8,8,0,0,1-16,0V123.31L93.66,141.66a8,8,0,0,1-11.32,0L64,123.31V152a8,8,0,0,1-16,0V104a8,8,0,0,1,13.66-5.66L88,124.69l26.34-26.35A8,8,0,0,1,128,104Zm77.66,18.34a8,8,0,0,1,0,11.32l-24,24a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L168,132.69V104a8,8,0,0,1,16,0v28.69l10.34-10.35A8,8,0,0,1,205.66,122.34Z"></path></svg>

After

Width:  |  Height:  |  Size: 555 B

1
assets/dist/icons/mastodon-logo.svg vendored Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M184,32H72A40,40,0,0,0,32,72V192a40,40,0,0,0,40,40h88a8,8,0,0,0,0-16H72a24,24,0,0,1-24-24v-8H184a40,40,0,0,0,40-40V72A40,40,0,0,0,184,32Zm24,112a24,24,0,0,1-24,24H48V72A24,24,0,0,1,72,48H184a24,24,0,0,1,24,24Zm-24-40v32a8,8,0,0,1-16,0V104a16,16,0,0,0-32,0v32a8,8,0,0,1-16,0V104a16,16,0,0,0-32,0v32a8,8,0,0,1-16,0V104a32,32,0,0,1,56-21.13A32,32,0,0,1,184,104Z"></path></svg>

After

Width:  |  Height:  |  Size: 482 B

1
assets/dist/icons/matrix-logo.svg vendored Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M72,216a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8V40a8,8,0,0,1,8-8H64a8,8,0,0,1,0,16H48V208H64A8,8,0,0,1,72,216ZM216,32H192a8,8,0,0,0,0,16h16V208H192a8,8,0,0,0,0,16h24a8,8,0,0,0,8-8V40A8,8,0,0,0,216,32Zm-32,88a32,32,0,0,0-56-21.13,31.93,31.93,0,0,0-40.71-6.15A8,8,0,0,0,72,96v64a8,8,0,0,0,16,0V120a16,16,0,0,1,32,0v40a8,8,0,0,0,16,0V120a16,16,0,0,1,32,0v40a8,8,0,0,0,16,0Z"></path></svg>

After

Width:  |  Height:  |  Size: 485 B

1
assets/dist/icons/network.svg vendored Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M232,112H136V88h8a16,16,0,0,0,16-16V40a16,16,0,0,0-16-16H112A16,16,0,0,0,96,40V72a16,16,0,0,0,16,16h8v24H24a8,8,0,0,0,0,16H56v32H48a16,16,0,0,0-16,16v32a16,16,0,0,0,16,16H80a16,16,0,0,0,16-16V176a16,16,0,0,0-16-16H72V128H184v32h-8a16,16,0,0,0-16,16v32a16,16,0,0,0,16,16h32a16,16,0,0,0,16-16V176a16,16,0,0,0-16-16h-8V128h32a8,8,0,0,0,0-16ZM112,40h32V72H112ZM80,208H48V176H80Zm128,0H176V176h32Z"></path></svg>

After

Width:  |  Height:  |  Size: 516 B

1
assets/dist/icons/pencil-ruler.svg vendored Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M208,32H160a16,16,0,0,0-16,16V208a16,16,0,0,0,16,16h48a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32Zm0,176H160V176h24a8,8,0,0,0,0-16H160V136h24a8,8,0,0,0,0-16H160V96h24a8,8,0,0,0,0-16H160V48h48V208ZM77.66,26.34a8,8,0,0,0-11.32,0l-32,32A8,8,0,0,0,32,64V208a16,16,0,0,0,16,16H96a16,16,0,0,0,16-16V64a8,8,0,0,0-2.34-5.66ZM48,176V80H64v96ZM80,80H96v96H80ZM72,43.31,92.69,64H51.31ZM48,208V192H96v16Z"></path></svg>

After

Width:  |  Height:  |  Size: 513 B

1
assets/dist/icons/video.svg vendored Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M164.44,105.34l-48-32A8,8,0,0,0,104,80v64a8,8,0,0,0,12.44,6.66l48-32a8,8,0,0,0,0-13.32ZM120,129.05V95l25.58,17ZM216,40H40A16,16,0,0,0,24,56V168a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40Zm0,128H40V56H216V168Zm16,40a8,8,0,0,1-8,8H32a8,8,0,0,1,0-16H224A8,8,0,0,1,232,208Z"></path></svg>

After

Width:  |  Height:  |  Size: 412 B

1
assets/dist/icons/webcam.svg vendored Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M168,104a40,40,0,1,0-40,40A40,40,0,0,0,168,104Zm-64,0a24,24,0,1,1,24,24A24,24,0,0,1,104,104Zm120,96H136V183.6a80,80,0,1,0-16,0V200H32a8,8,0,0,0,0,16H224a8,8,0,0,0,0-16ZM64,104a64,64,0,1,1,64,64A64.07,64.07,0,0,1,64,104Z"></path></svg>

After

Width:  |  Height:  |  Size: 343 B

33
data/finances.json Normal file
View file

@ -0,0 +1,33 @@
{
"2024": {
"4": {
"Membership Fees": {
"EUR": 365
},
"Donations": {},
"Server Costs": {
"EUR": -216.57
},
"Domain Names": {},
"Operating Expenses": {
"EUR": -36.10
},
"Conversions": {}
},
"5": {
"Membership Fees": {
"EUR": 390
},
"Donations": {
"BTC": 0.000434,
"XMR": 0.447661805527
},
"Server Costs": {
"EUR": -430.04
},
"Domain Names": {},
"Operating Expenses": {},
"Conversions": {}
}
}
}

View file

@ -12,6 +12,7 @@
"url": "https://element.private.coffee" "url": "https://element.private.coffee"
} }
], ],
"icon": "matrix-logo",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": true "exclude_from_simple": true
}, },
@ -27,6 +28,7 @@
"url": "https://cryptpad.private.coffee" "url": "https://cryptpad.private.coffee"
} }
], ],
"icon": "article-ny-times",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": false "exclude_from_simple": false
}, },
@ -42,6 +44,7 @@
"url": "https://piped.private.coffee" "url": "https://piped.private.coffee"
} }
], ],
"icon": "video",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": false "exclude_from_simple": false
}, },
@ -57,6 +60,7 @@
"url": "https://myip.coffee" "url": "https://myip.coffee"
} }
], ],
"icon": "network",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": false "exclude_from_simple": false
}, },
@ -72,6 +76,7 @@
"url": "https://invidious.private.coffee" "url": "https://invidious.private.coffee"
} }
], ],
"icon": "video",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": false "exclude_from_simple": false
}, },
@ -91,6 +96,7 @@
"url": "https://skrt.social" "url": "https://skrt.social"
} }
], ],
"icon": "mastodon-logo",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": false "exclude_from_simple": false
}, },
@ -106,6 +112,7 @@
"url": "https://git.private.coffee" "url": "https://git.private.coffee"
} }
], ],
"icon": "git-branch",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": false "exclude_from_simple": false
}, },
@ -121,6 +128,7 @@
"url": "https://bbb.private.coffee" "url": "https://bbb.private.coffee"
} }
], ],
"icon": "webcam",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": false "exclude_from_simple": false
}, },
@ -136,6 +144,7 @@
"url": "https://hedgedoc.private.coffee" "url": "https://hedgedoc.private.coffee"
} }
], ],
"icon": "markdown-logo",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": false "exclude_from_simple": false
}, },
@ -151,6 +160,7 @@
"url": "https://gothub.private.coffee" "url": "https://gothub.private.coffee"
} }
], ],
"icon": "git-branch",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": false "exclude_from_simple": false
}, },
@ -166,6 +176,7 @@
"url": "https://redlib.private.coffee" "url": "https://redlib.private.coffee"
} }
], ],
"icon": "chats",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": false "exclude_from_simple": false
}, },
@ -181,6 +192,7 @@
"url": "https://alltube.private.coffee" "url": "https://alltube.private.coffee"
} }
], ],
"icon": "video",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": false "exclude_from_simple": false
}, },
@ -196,6 +208,7 @@
"url": "https://structables.private.coffee" "url": "https://structables.private.coffee"
} }
], ],
"icon": "lightbulb",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": false "exclude_from_simple": false
}, },
@ -211,6 +224,7 @@
"url": "https://nocodb.private.coffee" "url": "https://nocodb.private.coffee"
} }
], ],
"icon": "database",
"exclude_from_index": true, "exclude_from_index": true,
"exclude_from_simple": true "exclude_from_simple": true
}, },
@ -226,6 +240,7 @@
"url": "https://penpot.private.coffee" "url": "https://penpot.private.coffee"
} }
], ],
"icon": "pencil-ruler",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": false "exclude_from_simple": false
}, },
@ -241,6 +256,7 @@
"url": "https://pcof.fi" "url": "https://pcof.fi"
} }
], ],
"icon": "link",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": false "exclude_from_simple": false
}, },
@ -256,6 +272,7 @@
"url": "https://rallly.private.coffee" "url": "https://rallly.private.coffee"
} }
], ],
"icon": "calendar",
"exclude_from_index": true, "exclude_from_index": true,
"exclude_from_simple": true "exclude_from_simple": true
}, },
@ -271,6 +288,7 @@
"url": "https://librey.private.coffee" "url": "https://librey.private.coffee"
} }
], ],
"icon": "magnifying-glass",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": false "exclude_from_simple": false
}, },
@ -286,6 +304,7 @@
"url": "https://overleaf.private.coffee" "url": "https://overleaf.private.coffee"
} }
], ],
"icon": "leaf",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": false "exclude_from_simple": false
}, },
@ -301,44 +320,9 @@
"url": "https://binternet.private.coffee" "url": "https://binternet.private.coffee"
} }
], ],
"icon": "images",
"exclude_from_index": false, "exclude_from_index": false,
"exclude_from_simple": false "exclude_from_simple": false
},
{
"name": "Nitter",
"url": "https://nitter.private.coffee",
"short_description": "Nitter is a privacy-friendly alternative front-end to Twitter.",
"long_description": "Nitter is a privacy-friendly alternative front-end to Twitter. It allows you to browse Twitter without being tracked.",
"status": "NOK",
"links": [
{
"name": "Go to Nitter",
"url": "https://nitter.private.coffee",
"alternatives": [
{
"name": "Tor (.onion)",
"url": "http://nitter.coffee2m3bjsrrqqycx6ghkxrnejl2q6nl7pjw2j4clchjj6uk5zozad.onion/"
}
]
}
],
"exclude_from_index": true,
"exclude_from_simple": true
},
{
"name": "Proxigram",
"url": "https://proxigram.private.coffee",
"short_description": "Proxigram is a privacy-friendly alternative front-end to Instagram.",
"long_description": "Proxigram is a privacy-friendly alternative front-end to Instagram. It allows you to browse Instagram without being tracked.",
"status": "NOK",
"links": [
{
"name": "Go to Proxigram",
"url": "https://proxigram.private.coffee"
}
],
"exclude_from_index": true,
"exclude_from_simple": true
} }
] ]
} }

201
helpers/finances.py Normal file
View file

@ -0,0 +1,201 @@
from decimal import Decimal
def get_latest_month(data):
years = sorted(data.keys())
latest_year = years[-1]
months = sorted(data[latest_year].keys())
latest_month = months[-1]
return int(latest_month), int(latest_year)
def get_transparency_data(data, year=None, month=None):
if year is None:
year = max(data.keys())
if month is None:
month = max(data[year].keys())
assert year in data, f"Year {year} not found in data"
assert month in data[year], f"Month {month}-{year} not found in data"
# Initialize balances
balances = {}
incomes = {}
expenses = {}
start_balance = {}
end_balance = {}
for y in sorted(data.keys()):
if int(y) > int(year):
break
for m in sorted(data[y].keys()):
if int(y) == int(year) and int(m) > int(month):
break
# If the month is the one we are interested in, capture the start balance
if int(y) == int(year) and int(m) == int(month):
start_balance = {k: Decimal(v) for k, v in balances.items()}
for category in data[y][m]:
for currency, amount in data[y][m][category].items():
if currency not in balances:
balances[currency] = Decimal(0)
balances[currency] += Decimal(str(amount))
# Track incomes and expenses
if int(y) == int(year) and int(m) == int(month):
if Decimal(str(amount)) > 0:
if category not in incomes:
incomes[category] = {}
if currency not in incomes[category]:
incomes[category][currency] = Decimal(0)
incomes[category][currency] += Decimal(str(amount))
else:
if category not in expenses:
expenses[category] = {}
if currency not in expenses[category]:
expenses[category][currency] = Decimal(0)
expenses[category][currency] += Decimal(str(amount))
# If the month is the one we are interested in, capture the end balance
if int(y) == int(year) and int(m) == int(month):
end_balance = {k: Decimal(v) for k, v in balances.items()}
# Calculate accumulated sums of incomes and expenses
accumulated_incomes = {
currency: sum(incomes[cat].get(currency, Decimal(0)) for cat in incomes)
for currency in balances
}
accumulated_expenses = {
currency: sum(expenses[cat].get(currency, Decimal(0)) for cat in expenses)
for currency in balances
}
return {
"start_balance": start_balance,
"end_balance": end_balance,
"incomes": incomes,
"expenses": expenses,
"accumulated_incomes": accumulated_incomes,
"accumulated_expenses": accumulated_expenses,
}
def generate_transparency_table(result, currencies=None):
def extract_currencies(data):
return ["EUR"] + (
list(
set(
list(data["start_balance"].keys())
+ list(data["end_balance"].keys())
+ list(data["accumulated_incomes"].keys())
+ list(data["accumulated_expenses"].keys())
)
- {"EUR"}
)
)
def format_currency(value, currency):
if currency == "EUR":
return f"{value:,.2f}"
elif currency in ["BTC", "ETH", "XMR"]:
return f"{value:,.9f} {currency}"
else:
return f"{value} {currency}"
def format_value(value, currency):
if value == 0:
return f"{format_currency(value, currency)}"
elif value > 0:
return f"+ {format_currency(value, currency)}"
else:
return f"- {format_currency(abs(value), currency)}"
html = """
<table class="table table-bordered table-transparency">
<thead class="table-light">
<tr>
<th scope="col">Category</th>
"""
if currencies is None:
currencies = extract_currencies(result)
# Add currency headers
for currency in currencies:
if currency == "EUR":
html += '<th class="currency-col" scope="col">Euros (€)</th>'
elif currency == "BTC":
html += '<th class="currency-col" scope="col">Bitcoin (BTC)</th>'
elif currency == "ETH":
html += '<th class="currency-col" scope="col">Ethereum (ETH)</th>'
elif currency == "XMR":
html += '<th class="currency-col" scope="col">Monero (XMR)</th>'
else:
html += f'<th class="currency-col" scope="col">{currency}</th>'
html += """
</tr>
</thead>
<tbody>
"""
# Add start balance row
html += "<tr><td>Account Balance (start of month)</td>"
for currency in currencies:
value = result["start_balance"].get(currency, Decimal(0))
html += f"<td>{format_value(value, currency)}</td>"
html += "</tr>"
# Add income rows
for category, transactions in result["incomes"].items():
html += f"<tr><td>{category}</td>"
for currency in currencies:
value = transactions.get(currency, "")
if value != "":
html += f"<td>{format_value(value, currency)}</td>"
else:
html += "<td></td>"
html += "</tr>"
# Add expense rows
for category, transactions in result["expenses"].items():
html += f"<tr><td>{category}</td>"
for currency in currencies:
value = transactions.get(currency, "")
if value != "":
html += f"<td>{format_value(value, currency)}</td>"
else:
html += "<td></td>"
html += "</tr>"
# Add total income row
html += '<tr class="table-secondary"><td><b>Total Income</b></td>'
for currency in currencies:
value = result["accumulated_incomes"].get(currency, Decimal(0))
html += f"<td><b>{format_value(value, currency)}</b></td>"
html += "</tr>"
# Add total expenses row
html += '<tr class="table-secondary"><td><b>Total Expenses</b></td>'
for currency in currencies:
value = result["accumulated_expenses"].get(currency, Decimal(0))
html += f"<td><b>{format_value(value, currency)}</b></td>"
html += "</tr>"
# Add end balance row
html += '<tr class="table-secondary"><td><b>Account Balance (end of month)</b></td>'
for currency in currencies:
value = result["end_balance"].get(currency, Decimal(0))
html += f"<td><b>{format_value(value, currency)}</b></td>"
html += "</tr>"
html += """
</tbody>
</table>
"""
return html

75
main.py
View file

@ -3,9 +3,17 @@ from jinja2 import TemplateNotFound
import json import json
import pathlib import pathlib
import os
import datetime
from argparse import ArgumentParser from argparse import ArgumentParser
from helpers.finances import (
generate_transparency_table,
get_transparency_data,
get_latest_month,
)
app = Flask(__name__) app = Flask(__name__)
@ -18,18 +26,79 @@ def send_assets(path):
@app.route("/<path:path>.html") @app.route("/<path:path>.html")
def catch_all(path): def catch_all(path):
try: try:
services = json.loads( kwargs = {}
(pathlib.Path(__file__).parent / "services.json").read_text()
if app.development_mode:
kwargs.update(
{
"warning": render_template("prod-warning.html"),
}
) )
return render_template(f"{path}.html", services=services)
if path in (
"index",
"simple",
):
services = json.loads(
(pathlib.Path(__file__).parent / "data" / "services.json").read_text()
)
kwargs.update(
{
"services": services,
}
)
if path == "membership":
finances = json.loads(
(pathlib.Path(__file__).parent / "data" / "finances.json").read_text()
)
finances_month, finances_year = get_latest_month(finances)
finances_period = datetime.date(finances_year, finances_month, 1)
finances_period_str = finances_period.strftime("%B %Y")
finances_table = generate_transparency_table(
get_transparency_data(finances)
)
kwargs.update(
{
"finances": finances_table,
"finances_period": finances_period_str,
}
)
return render_template(f"{path}.html", **kwargs)
except TemplateNotFound: except TemplateNotFound:
return "404 Not Found", 404 return "404 Not Found", 404
app.development_mode = False
if os.environ.get("PRIVATECOFFEE_DEV"):
app.development_mode = True
def icon(icon_name):
file = send_from_directory("assets", f"dist/icons/{icon_name}.svg")
try:
file_content = file.response.file.read().decode("utf-8")
except AttributeError:
file_content = file.response.read().decode("utf-8")
return file_content
app.add_template_filter(icon)
if __name__ == "__main__": if __name__ == "__main__":
parser = ArgumentParser(description="Run the private.coffee web server.") parser = ArgumentParser(description="Run the private.coffee web server.")
parser.add_argument("--port", type=int, default=9810) parser.add_argument("--port", type=int, default=9810)
parser.add_argument("--debug", action="store_true") parser.add_argument("--debug", action="store_true")
parser.add_argument("--dev", action="store_true")
args = parser.parse_args() args = parser.parse_args()
app.development_mode = args.dev or app.development_mode
app.run(port=args.port, debug=args.debug) app.run(port=args.port, debug=args.debug)

View file

@ -51,6 +51,7 @@
</ul><a class="btn btn-primary shadow navbar-btn" role="button" href="/membership.html">JOIN &amp; REBEL</a> </ul><a class="btn btn-primary shadow navbar-btn" role="button" href="/membership.html">JOIN &amp; REBEL</a>
</div> </div>
</nav> </nav>
{% if warning %}{{ warning|safe }}{% endif %}
{% block content %}{% endblock %} {% block content %}{% endblock %}
<footer class="bg-primary-gradient"> <footer class="bg-primary-gradient">
<div class="container py-4 py-lg-5"> <div class="container py-4 py-lg-5">
@ -74,26 +75,12 @@
<div class="fw-bold d-flex align-items-center mb-2"> <div class="fw-bold d-flex align-items-center mb-2">
<span <span
class="bs-icon-sm bs-icon-circle bs-icon-primary d-flex justify-content-center align-items-center bs-icon me-2" class="bs-icon-sm bs-icon-circle bs-icon-primary d-flex justify-content-center align-items-center bs-icon me-2"
><svg >{{ "coffee" | icon | safe }}</span
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
fill="currentColor"
viewBox="0 0 16 16"
class="bi bi-bezier"
>
<path
fill-rule="evenodd"
d="M0 10.5A1.5 1.5 0 0 1 1.5 9h1A1.5 1.5 0 0 1 4 10.5v1A1.5 1.5 0 0 1 2.5 13h-1A1.5 1.5 0 0 1 0 11.5zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5zm10.5.5A1.5 1.5 0 0 1 13.5 9h1a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5h-1a1.5 1.5 0 0 1-1.5-1.5zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5zM6 4.5A1.5 1.5 0 0 1 7.5 3h1A1.5 1.5 0 0 1 10 4.5v1A1.5 1.5 0 0 1 8.5 7h-1A1.5 1.5 0 0 1 6 5.5zM7.5 4a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5z"
></path>
<path
d="M6 4.5H1.866a1 1 0 1 0 0 1h2.668A6.517 6.517 0 0 0 1.814 9H2.5c.123 0 .244.015.358.043a5.517 5.517 0 0 1 3.185-3.185A1.503 1.503 0 0 1 6 5.5zm3.957 1.358A1.5 1.5 0 0 0 10 5.5v-1h4.134a1 1 0 1 1 0 1h-2.668a6.517 6.517 0 0 1 2.72 3.5H13.5c-.123 0-.243.015-.358.043a5.517 5.517 0 0 0-3.185-3.185z"
></path></svg></span
><span>Private.coffee</span> ><span>Private.coffee</span>
</div> </div>
<p class="text-muted"> <p class="text-muted">
Private.coffee is a collection of services that respect your Private.coffee is a privacy-focused non-profit association, dedicated
privacy. to supporting privacy and digital sovereignty.
</p> </p>
</div> </div>
</div> </div>

View file

@ -29,10 +29,9 @@
<div class="col mb-5"> <div class="col mb-5">
<div class="card shadow-sm"> <div class="card shadow-sm">
<div class="card-body px-4 py-5 px-md-5"> <div class="card-body px-4 py-5 px-md-5">
<div class="bs-icon-lg d-flex justify-content-center align-items-center mb-3 bs-icon" style="top: 1rem;right: 1rem;position: absolute;"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-chat-text text-primary"> <div class="bs-icon-lg d-flex justify-content-center align-items-center mb-3 bs-icon" style="top: 1rem;right: 1rem;position: absolute;">
<path d="M2.678 11.894a1 1 0 0 1 .287.801 10.97 10.97 0 0 1-.398 2c1.395-.323 2.247-.697 2.634-.893a1 1 0 0 1 .71-.074A8.06 8.06 0 0 0 8 14c3.996 0 7-2.807 7-6 0-3.192-3.004-6-7-6S1 4.808 1 8c0 1.468.617 2.83 1.678 3.894m-.493 3.905a21.682 21.682 0 0 1-.713.129c-.2.032-.352-.176-.273-.362a9.68 9.68 0 0 0 .244-.637l.003-.01c.248-.72.45-1.548.524-2.319C.743 11.37 0 9.76 0 8c0-3.866 3.582-7 8-7s8 3.134 8 7-3.582 7-8 7a9.06 9.06 0 0 1-2.347-.306c-.52.263-1.639.742-3.468 1.105z"></path> {% if service.icon %}{{ service.icon | icon | safe }}{% endif %}
<path d="M4 5.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8m0 2.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5"></path> </div>
</svg></div>
<h5 class="fw-bold card-title">{{ service.name }}</h5> <h5 class="fw-bold card-title">{{ service.name }}</h5>
<p class="text-muted card-text mb-4">{{ service.long_description }}</p> <p class="text-muted card-text mb-4">{{ service.long_description }}</p>
{% for link in service.links %} {% for link in service.links %}
@ -92,9 +91,7 @@
<div class="col-md-4 col-xl-4 d-flex justify-content-center justify-content-xl-start"> <div class="col-md-4 col-xl-4 d-flex justify-content-center justify-content-xl-start">
<div class="d-flex flex-wrap flex-md-column justify-content-md-start align-items-md-start h-100"> <div class="d-flex flex-wrap flex-md-column justify-content-md-start align-items-md-start h-100">
<div class="d-flex align-items-center p-3"> <div class="d-flex align-items-center p-3">
<div class="bs-icon-md bs-icon-circle bs-icon-primary shadow d-flex flex-shrink-0 justify-content-center align-items-center d-inline-block bs-icon bs-icon-md"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-envelope"> <div class="bs-icon-md bs-icon-circle bs-icon-primary shadow d-flex flex-shrink-0 justify-content-center align-items-center d-inline-block bs-icon bs-icon-md">{{ "envelope" | icon | safe }}</div>
<path d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v.217l7 4.2 7-4.2V4a1 1 0 0 0-1-1zm13 2.383-4.708 2.825L15 11.105zm-.034 6.876-5.64-3.471L8 9.583l-1.326-.795-5.64 3.47A1 1 0 0 0 2 13h12a1 1 0 0 0 .966-.741M1 11.105l4.708-2.897L1 5.383z"></path>
</svg></div>
<div class="px-2"> <div class="px-2">
<h6 class="fw-bold mb-0">Email</h6> <h6 class="fw-bold mb-0">Email</h6>
<p class="text-muted mb-0">support@private.coffee</p> <p class="text-muted mb-0">support@private.coffee</p>
@ -107,9 +104,7 @@
<div class="col-md-4 col-xl-4 d-flex justify-content-center justify-content-xl-start"> <div class="col-md-4 col-xl-4 d-flex justify-content-center justify-content-xl-start">
<div class="d-flex flex-wrap flex-md-column justify-content-md-start align-items-md-start h-100"> <div class="d-flex flex-wrap flex-md-column justify-content-md-start align-items-md-start h-100">
<div class="d-flex align-items-center p-3"> <div class="d-flex align-items-center p-3">
<div class="bs-icon-md bs-icon-circle bs-icon-primary shadow d-flex flex-shrink-0 justify-content-center align-items-center d-inline-block bs-icon bs-icon-md"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-envelope"> <div class="bs-icon-md bs-icon-circle bs-icon-primary shadow d-flex flex-shrink-0 justify-content-center align-items-center d-inline-block bs-icon bs-icon-md">{{ "matrix-logo" | icon | safe }}</div>
<path d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v.217l7 4.2 7-4.2V4a1 1 0 0 0-1-1zm13 2.383-4.708 2.825L15 11.105zm-.034 6.876-5.64-3.471L8 9.583l-1.326-.795-5.64 3.47A1 1 0 0 0 2 13h12a1 1 0 0 0 .966-.741M1 11.105l4.708-2.897L1 5.383z"></path>
</svg></div>
<div class="px-2"> <div class="px-2">
<h6 class="fw-bold mb-0">Matrix</h6> <h6 class="fw-bold mb-0">Matrix</h6>
<p class="text-muted mb-0"><a href="https://matrix.pcof.fi/#/#private.coffee:private.coffee">#private.coffee:private.coffee</a></p> <p class="text-muted mb-0"><a href="https://matrix.pcof.fi/#/#private.coffee:private.coffee">#private.coffee:private.coffee</a></p>

View file

@ -1,7 +1,7 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block title %}Legal Notice{% endblock %} {% block title %}Legal Notice{% endblock %}
{% block content %} {% block content %}
<section class="bg-primary-gradient"> <section>
<div class="container py-5"> <div class="container py-5">
<div class="row align-items-center"> <div class="row align-items-center">
<div class="col"> <div class="col">
@ -20,7 +20,6 @@
</div> </div>
<div class="container"> <div class="container">
<h1>Legal Notice</h1>
<p>This is a legal notice for the website private.coffee</p> <p>This is a legal notice for the website private.coffee</p>
<p>The website private.coffee is run by the following entity:</p> <p>The website private.coffee is run by the following entity:</p>
<address> <address>

View file

@ -1,37 +1,96 @@
{% extends "base.html" %} {% extends "base.html" %} {% block title %}Membership / Donations{% endblock %}
{% block title %}Membership / Donations{% endblock %}
{% block content %} {% block content %}
<div class="container"> <div class="container my-5">
<h1>Membership/Donations</h1> <div class="text-center mb-5">
<p> <h1 class="special-header fancy-text-primary">Membership/Donations</h1>
private.coffee is a non-profit organization dedicated to supporting privacy <p class="lead">
and digital sovereignty. We fund our server infrastructure through donations Private.coffee is a non-profit organization dedicated to supporting
and membership fees. privacy and digital sovereignty. We fund our activities and running
</p> infrastructure costs through membership fees. Donations allow us to expand
<p> our services and reach more people.
Membership fees help cover the costs of server infrastructure, domain names,
and other operating expenses. Likewise, all donations contribute towards
these ongoing costs.
</p>
<p>
Supporting the private.coffee project is possible by joining our association
or by making a direct donation.
</p>
<div class="donation-details">
<p><b>Donations:</b></p>
<p>
Bank private.coffee - Verein zur Förderung von Privatsphäre und digitaler
Souveränität
</p>
<p>IBAN: AT35 2081 5000 4554 0812</p>
<p>BIC: STSPAT2GXXX</p>
<p>
For donation listing preferences, please specify in the note to payee.
</p> </p>
</div> </div>
<div class="zvr-number"> <div class="row">
<p>Central Register of Associations (ZVR) Number: 1758485319</p> <div class="col-md-4 mb-4">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title">Membership</h5>
<p class="card-text">
Membership fees help cover the costs of our day-to-day activities,
server infrastructure, domain names, and other running operating
expenses. This allows us to provide services to our members and the
public.
</p>
<p class="card-text">
If you're interested in joining our association, get in touch with
us for more information.
</p>
</div>
</div>
</div>
<div class="col-md-4 mb-4">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title">Bank Donations</h5>
<p class="card-text">
Even if you're not a member, you can still support us by making a
direct donation to our bank account. Your donation will be used to
fund our activities and expand our services.
</p>
<p class="card-text"><b>Account holder:</b> Private.coffee</p>
<p class="card-text"><b>IBAN:</b> AT35 2081 5000 4554 0812</p>
<p class="card-text"><b>BIC:</b> STSPAT2GXXX</p>
</div>
</div>
</div>
<div class="col-md-4 mb-4">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title">Crypto Donations</h5>
<p class="card-text">
While our expenses are generally in fiat currency, we accept
donations in cryptocurrencies, too.
</p>
<p class="card-text">
<b>Bitcoin (BTC):</b>
<code>bc1qnu7r5sed4afacfpgx5za8hsyhaj4rs45dpm26k</code>
</p>
<p class="card-text">
<b>Monero (XMR):</b>
<code
>487Ny4iBk2pKGJwjyYrumFD8xFmrS6jCSXNA8e5EvVJ49GyS54CRDVz514MBnXgNT1EioKYiagHs33sLzUAFj8i3Pwg3AMS</code
>
</p>
<p class="card-text">
<b>Ethereum (ETH):</b> <code>Coming soon&trade;</code>
</p>
<p class="card-text">
If your client supports OpenAlias, you can just send your donation
to <code>private.coffee</code>.
</p>
</div>
</div>
</div>
</div>
<div class="card shadow-sm mt-4">
<div class="card-body">
<h5 class="card-title">Transparency Report for {{ finances_period }}</h5>
<p class="card-text">
We believe in transparency and accountability. Below is a summary of our
income and expenses for the last month, so you can see how your
donations are being used.
</p>
<div class="table-responsive">{{ finances|safe }}</div>
</div>
</div>
<div class="card shadow-sm mt-4">
<div class="card-body">
<h5>Central Register of Associations (ZVR) Number: 1758485319</h5>
<p> <p>
Our statutes can be found in our Git Our statutes can be found in our Git
<a href="https://git.private.coffee/PrivateCoffee/statuten" <a href="https://git.private.coffee/PrivateCoffee/statuten"
@ -43,14 +102,15 @@
>in English</a >in English</a
>. >.
</p> </p>
<p class="contact-info"> <p class="contact-info" id="contact-info">
Interested in joining the association? Reach out via Interested in joining the association? Reach out via
<a href="mailto:support@private.coffee">email</a> or <a href="mailto:support@private.coffee">email</a> or
<a href="https://matrix.private.cf/#/#private.coffee:private.coffee" <a href="https://matrix.pcof.fi/#/#private.coffee:private.coffee"
>Matrix</a >Matrix</a
> >
for more information. for more information.
</p> </p>
</div> </div>
</div> </div>
</div>
{% endblock %} {% endblock %}

View file

@ -1,12 +1,14 @@
{% extends "base.html" %} {% extends "base.html" %} {% block title %}Privacy Policy{% endblock %}
{% block title %}Privacy Policy{% endblock %}
{% block content %} {% block content %}
<div class="container"> <div class="container">
<h1>Privacy Policy</h1> <div class="text-center mb-5">
<p> <h1 class="special-header fancy-text-primary">Privacy Policy</h1>
This is the privacy policy for the website private.coffee. It describes how <p class="lead">
we collect and use your personal data. This is the privacy policy for the website private.coffee. It describes
how we collect and use your personal data.
</p> </p>
</div>
<div class="section">
<p> <p>
This privacy policy is effective as of 2024-04-26. It may be updated from This privacy policy is effective as of 2024-04-26. It may be updated from
time to time, so please check back regularly. time to time, so please check back regularly.
@ -15,6 +17,8 @@
If you have any questions about this privacy policy, please contact us at If you have any questions about this privacy policy, please contact us at
<a href="mailto:support@private.coffee">support@private.coffee</a>. <a href="mailto:support@private.coffee">support@private.coffee</a>.
</p> </p>
</div>
<div class="section">
<h2>Who are we?</h2> <h2>Who are we?</h2>
<p>The data controller for private.coffee is:</p> <p>The data controller for private.coffee is:</p>
<address> <address>
@ -30,6 +34,8 @@
Email: Email:
<a href="mailto:support@private.coffee">support@private.coffee</a> <a href="mailto:support@private.coffee">support@private.coffee</a>
</p> </p>
</div>
<div class="section">
<h2>What data do we collect?</h2> <h2>What data do we collect?</h2>
<p>We collect the following data from you:</p> <p>We collect the following data from you:</p>
<ul> <ul>
@ -38,8 +44,8 @@
some of our services. some of our services.
</li> </li>
<li> <li>
Any data you provide to us, such as your email address, when you create an Any data you provide to us, such as your email address, when you create
account on one of our services. an account on one of our services.
</li> </li>
<li> <li>
Usage data that is collected automatically by our services, such as the Usage data that is collected automatically by our services, such as the
@ -47,10 +53,12 @@
well as any content you create using our services. well as any content you create using our services.
</li> </li>
<li> <li>
Any information, including personal data and payment information, that you Any information, including personal data and payment information, that
provide to us when you make a donation or join our association. you provide to us when you make a donation or join our association.
</li> </li>
</ul> </ul>
</div>
<div class="section">
<h2>How do we use your data?</h2> <h2>How do we use your data?</h2>
<p> <p>
We use your data to provide you with the services you requested. This We use your data to provide you with the services you requested. This
@ -63,20 +71,26 @@
<li>Providing support to you</li> <li>Providing support to you</li>
<li>Processing donations and memberships</li> <li>Processing donations and memberships</li>
</ul> </ul>
<p>All of those are what is called "legitimate interests" in legal speak.</p> <p>
All of those are what is called "legitimate interests" in legal speak.
</p>
<p> <p>
We do not use your data for any other purposes, including marketing, We do not use your data for any other purposes, including marketing,
advertising, or tracking, we do not share your data with third parties advertising, or tracking, we do not share your data with third parties
(unless required by law), we do not use your data to create profiles or make (unless required by law), we do not use your data to create profiles or
automated decisions, and we do not cross-reference your data between make automated decisions, and we do not cross-reference your data between
different services or any other sources. different services or any other sources.
</p> </p>
</div>
<div class="section">
<h2>Where do we store your data?</h2> <h2>Where do we store your data?</h2>
<p> <p>
We store your data on our web servers, which are located in Austria. We also We store your data on our web servers, which are located in Austria. We
use servers in Germany, but those are not public-facing and do not store or also use servers in Germany, but those are not public-facing and do not
process any personal data. store or process any personal data.
</p> </p>
</div>
<div class="section">
<h2>How long do we store your data?</h2> <h2>How long do we store your data?</h2>
<ul> <ul>
<li> <li>
@ -84,30 +98,33 @@
After that, the log files that contain them are deleted automatically. After that, the log files that contain them are deleted automatically.
</li> </li>
<li> <li>
Data associated with an account you have on one of our services is stored Data associated with an account you have on one of our services is
for as long as you have an account on that service. If you delete your stored for as long as you have an account on that service. If you delete
account, your data will be deleted automatically. The service will have a your account, your data will be deleted automatically. The service will
dedicated privacy policy, please consult that if you have any specific have a dedicated privacy policy, please consult that if you have any
questions. specific questions.
</li> </li>
<li> <li>
If you send a support request to us, we will store your email address and If you send a support request to us, we will store your email address
any other data you provide to us for up to 30 days in our support system. and any other data you provide to us for up to 30 days in our support
After that, the data will be deleted automatically. system. After that, the data will be deleted automatically.
</li> </li>
<li> <li>
Data associated with a donation is stored for as long as required by law, Data associated with a donation is stored for as long as required by
which is currently 7 years in Austria. After that, the data will be law, which is currently 7 years in Austria. After that, the data will be
deleted. deleted.
</li> </li>
<li> <li>
Data associated with a membership is stored for as long as you are a Data associated with a membership is stored for as long as you are a
member of our association. If you leave the association, your data will be member of our association. If you leave the association, your data will
deleted automatically. This does not apply to data that is required by law be deleted automatically. This does not apply to data that is required
to be stored for a longer period of time, such as financial records, which by law to be stored for a longer period of time, such as financial
are stored for 7 years regardless of your membership status. records, which are stored for 7 years regardless of your membership
status.
</li> </li>
</ul> </ul>
</div>
<div class="section">
<h2>What are your data protection rights?</h2> <h2>What are your data protection rights?</h2>
<p>You have the following data protection rights:</p> <p>You have the following data protection rights:</p>
<ul> <ul>
@ -127,10 +144,10 @@
<a href="mailto:support@private.coffee">support@private.coffee</a>. <a href="mailto:support@private.coffee">support@private.coffee</a>.
</p> </p>
<p> <p>
Your privacy is important to us - after all, that's why we're all here - and Your privacy is important to us - after all, that's why we're all here -
we will do our best to respond to your request as soon as possible. Please and we will do our best to respond to your request as soon as possible.
note that we may need to verify your identity before we can respond to your Please note that we may need to verify your identity before we can respond
request - we will not share your data with anyone else. to your request - we will not share your data with anyone else.
</p> </p>
<p> <p>
If you are not satisfied with our response, or believe that we are If you are not satisfied with our response, or believe that we are
@ -143,15 +160,17 @@
help you out directly, and are always open to suggestions for improvement, help you out directly, and are always open to suggestions for improvement,
so please do get in touch with us if you have any questions or concerns. so please do get in touch with us if you have any questions or concerns.
</p> </p>
</div>
<div class="section">
<h2>What are cookies?</h2> <h2>What are cookies?</h2>
<p> <p>
Cookies are small text files that are placed on your computer or mobile Cookies are small text files that are placed on your computer or mobile
device when you visit a website. They are widely used to make websites work, device when you visit a website. They are widely used to make websites
or work more efficiently, as well as to provide information to the owners of work, or work more efficiently, as well as to provide information to the
the site. Cookies are stored on your device, and can be accessed by the owners of the site. Cookies are stored on your device, and can be accessed
website that created them. They are not harmful to your device, and do not by the website that created them. They are not harmful to your device, and
directly contain any personal data, but are used by our services to identify do not directly contain any personal data, but are used by our services to
you between multiple visits. identify you between multiple visits.
</p> </p>
<p> <p>
Cookies are used on some of our services to provide you with a better Cookies are used on some of our services to provide you with a better
@ -159,9 +178,10 @@
settings - for example, to allow you to login to our services - and to settings - for example, to allow you to login to our services - and to
provide you with a better experience when browsing our services. We do not provide you with a better experience when browsing our services. We do not
use cookies to track your activity, either on our services or on other use cookies to track your activity, either on our services or on other
websites. In legal/technical terms, we exclusively use "strictly necessary" websites. In legal/technical terms, we exclusively use "strictly
first-party cookies, which is also why you don't see any cookie banners on necessary" first-party cookies, which is also why you don't see any cookie
our website. banners on our website.
</p> </p>
</div> </div>
</div>
{% endblock %} {% endblock %}

View file

@ -0,0 +1,6 @@
<div class="alert alert-warning text-center" role="alert">
This is a development version of the Private.coffee website. For the live
version, please visit
<a href="https://private.coffee" class="alert-link">https://private.coffee</a
>.
</div>

View file

@ -8,7 +8,15 @@
<body> <body>
<div style="font-family: Arial, sans-serif; background-color: #f2f2f2; color: #333; line-height: 1.6; padding: 20px; max-width: 600px; margin: auto;"> <div style="font-family: Arial, sans-serif; background-color: #f2f2f2; color: #333; line-height: 1.6; padding: 20px; max-width: 600px; margin: auto;">
<h2 style="color: #333;">Welcome to Private.coffee</h2> <h2 style="color: #333;">Welcome to Private.coffee</h2>
<p>Thanks for using our Element instance. Private.coffee is a collection of services that respect your privacy, here are some others:</p> <p>Thanks for using our Element instance! Now, why don't you join our rooms?</p>
<ul style="list-style: none; padding: 0;">
<li style="padding: 8px 0;"><a style="color: #1a5dab; text-decoration: none;" href="https://element.private.coffee/#/#private-coffee:private.coffee">#private-coffee:private.coffee</a> - The Private.coffee Space, containing all rooms</li>
<li style="padding: 8px 0;"><a style="color: #1a5dab; text-decoration: none;" href="https://element.private.coffee/#/#private.coffee:private.coffee">#private.coffee:private.coffee</a> - General support for our services</li>
<li style="padding: 8px 0;"><a style="color: #1a5dab; text-decoration: none;" href="https://element.private.coffee/#/#matrix:private.coffee">#matrix:private.coffee</a> - Support for our Matrix server</li>
<li style="padding: 8px 0;"><a style="color: #1a5dab; text-decoration: none;" href="https://element.private.coffee/#/#coffeebreak:private.coffee">#coffeebreak:private.coffee</a> - ☕ Coffee Break ☕ - our off-topic room</li>
</ul>
<hr>
<p>Private.coffee operates a collection of services that respect your privacy, here are some others:</p>
<ul style="list-style: none; padding: 0;"> <ul style="list-style: none; padding: 0;">
{% for service in services.services %} {% for service in services.services %}
{% if not service.exclude_from_simple %} {% if not service.exclude_from_simple %}

View file

@ -2,12 +2,15 @@
{% block title %}Terms of Service{% endblock %} {% block title %}Terms of Service{% endblock %}
{% block content %} {% block content %}
<div class="container"> <div class="container">
<h1>Terms of Service</h1> <div class="text-center mb-5">
<p> <h1 class="special-header fancy-text-primary">Terms of Service</h1>
<p class="lead">
These are the terms of service for the website private.coffee and all These are the terms of service for the website private.coffee and all
services provided under this domain and its subdomains. Please read them services provided under this domain and its subdomains. Please read them
carefully. carefully.
</p> </p>
</div>
<div class="section">
<h2>1. Who are we?</h2> <h2>1. Who are we?</h2>
<p>The website private.coffee is run by:</p> <p>The website private.coffee is run by:</p>
<address> <address>
@ -23,12 +26,15 @@
Email: Email:
<a href="mailto:support@private.coffee">support@private.coffee</a> <a href="mailto:support@private.coffee">support@private.coffee</a>
</p> </p>
</div>
<div class="section">
<h2>2. What services do we provide?</h2> <h2>2. What services do we provide?</h2>
<p> <p>
The website private.coffee provides a collection of services that respect The website private.coffee provides a collection of services that respect
your privacy. These services include: your privacy. These services include:
</p> </p>
<ul> <ul>
<li>Information about the Private.coffee association</li>
<li> <li>
Proxy servers to several proprietary services (like YouTube, Twitter, Proxy servers to several proprietary services (like YouTube, Twitter,
etc.) etc.)
@ -40,6 +46,8 @@
You can find more information about these services on the You can find more information about these services on the
<a href="/">main page</a>. <a href="/">main page</a>.
</p> </p>
</div>
<div class="section">
<h2>3. What are your obligations?</h2> <h2>3. What are your obligations?</h2>
<p> <p>
a. We provide these services to you for free. In return, we ask you to a. We provide these services to you for free. In return, we ask you to
@ -93,6 +101,8 @@
reason. We will try to give you as much notice as possible before doing so, reason. We will try to give you as much notice as possible before doing so,
but we are not required to do so. but we are not required to do so.
</p> </p>
</div>
<div class="section">
<h2>4. What are our obligations?</h2> <h2>4. What are our obligations?</h2>
<p> <p>
a. We will do our best to provide you with a stable and reliable service. a. We will do our best to provide you with a stable and reliable service.
@ -141,4 +151,5 @@
We may also report the users involved to the appropriate authorities. We may also report the users involved to the appropriate authorities.
</p> </p>
</div> </div>
</div>
{% endblock %} {% endblock %}