diff --git a/.github/workflows/update-public-instances.yml b/.github/workflows/update-public-instances.yml new file mode 100644 index 0000000000..5571156ad9 --- /dev/null +++ b/.github/workflows/update-public-instances.yml @@ -0,0 +1,35 @@ +name: Update public instances +on: + schedule: [{cron: "0 0 * * *"}] + +jobs: + run: + name: Update public instances + runs-on: ubuntu-latest + steps: + - name: Checkout matrix.org source + uses: actions/checkout@v4 + with: + path: 'morg' + + - name: Checkout the public instance updater + uses: actions/checkout@v4 + with: + repository: 'thibaultamartin/public-instances-updater' + path: 'piu' + + - name: Update public instance data on the runner + run: | + cp morg/content/public-instances/instances.toml piu/instances.toml + cd piu && yarn && yarn run update && cd .. + cp piu/instances.toml morg/content/public-instances/instances.toml + + # Delete the if before merging to main + - name: Commit and push data (scheduled) + run: | + git config --global user.name "GitHub CI" + git config --global user.email "noreply@matrix.org" + git add content/public-instances/instances.toml + git commit -m "Update instances.toml" + git push + working-directory: morg diff --git a/content/public-instances/_index.md b/content/public-instances/_index.md new file mode 100644 index 0000000000..450ae3d405 --- /dev/null +++ b/content/public-instances/_index.md @@ -0,0 +1,7 @@ ++++ +title = "Matrix Server List" +template = "public-instances.html" +extra.summary = """ +Find a server to securely host your Matrix account. +""" ++++ diff --git a/content/public-instances/instances.toml b/content/public-instances/instances.toml new file mode 100644 index 0000000000..d00e4b1553 --- /dev/null +++ b/content/public-instances/instances.toml @@ -0,0 +1,36 @@ +[[instances]] +title = "archaeo.social" +domain = "archaeo.social" +location = "CH" +hoster = "The archaeo social collective" +structure = "non-profit" +terms_of_service = "https://archaeo.social/about" +software = "Synapse" +version = "1.87.0" +creation_date = "1950-01-01" +description = """ +An archaeology oriented instance. +""" + + [instances.signup] + requires_email = true + requires_captcha = true + +[[instances]] +title = "Matrix.org" +domain = "matrix.org" +location = "GB" +hoster = "The Matrix.org Foundation" +structure = "non-profit" +software = "Synapse" +version = "1.92.1 (b=matrix-org-hotfixes,3bb8cce692)" +privacy_policy = "https://matrix.org/legal/privacy-notice/" +terms_of_service = "https://matrix.org/legal/terms-and-conditions/" +creation_date = "2014-09-01" +description = """ +The largest open network for secure, decentralised communications. +""" + + [instances.signup] + requires_email = true + requires_captcha = true diff --git a/sass/_public-instances.scss b/sass/_public-instances.scss new file mode 100644 index 0000000000..d5659d8388 --- /dev/null +++ b/sass/_public-instances.scss @@ -0,0 +1,176 @@ +.public-instances { + + .total-and-filters { + display: flex; + flex-direction: row; + justify-content: space-between; + flex-wrap: wrap; + + .filters { + margin-inline: 0; + } + + .total { + font-weight: 700; + } + } + + #all-instances { + .project-card { + + color: var(--color-text); + text-align: center; + text-decoration: none; + + &:hover { + color: var(--color-text); + } + + p { + line-height: 140%; + } + } + } + + ul.details { + padding: 0; + display: flex; + gap: .2rem; + flex-wrap: wrap; + justify-content: center; + margin-block-start: auto; + + li { + list-style: none; + background: #E9E9E9; + border-radius: 16px; + padding: .375rem .625rem; + + font-style: normal; + font-weight: 400; + font-size: 1rem; + line-height: 120%; + color: #000000; + } + } + + .avatar { + width: 60px; + height: 60px; + background-color: #000000; + color: #fff; + display: grid; + place-content: center; + font-size: 32px; + clip-path: circle(30px); + } + + .dialog { + display: none; + background-color: #fff;; + border: 2px solid #d2d2d2; + border-radius: 20px; + position: fixed; + padding: 2.5rem 1.5rem; + z-index: 200; + + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + + overflow: auto; + + @media (max-width: 767px) { + left: -2px; + right: -2px; + top: 20%; + bottom: -20px; + padding-block-end: calc(2.5rem + 20px); + transform: unset; + } + + &.display { + display: block; + } + + a { + color: #000; + font-weight: 700; + text-decoration: underline; + } + + form { + display: flex; + } + + .close-button { + background-color: #000000; + border-color: transparent; + display: grid; + place-content: center; + padding: 10px; + clip-path: circle(15px at center); + + position: absolute; + top: 1rem; + right: 1rem; + + img { + width: 10px; + height: 10px; + } + } + + .instance-header { + display: flex; + gap: 1rem; + margin-inline-end: 3rem; + flex-wrap: wrap; + + .avatar { + margin-block: auto; + } + + .title-row { + display: flex; + justify-content: flex-start; + gap: 1rem; + flex-wrap: wrap; + + ul.details { + margin-block: auto; + } + } + } + + .instance-body { + padding-block: 0; + display: grid; + grid-template-columns: repeat(2, 1fr); + @media (max-width: 767px) { + grid-template-columns: 1fr; + } + gap: 2rem; + + h2 { + font-size: 1.1rem; + border-block-end: 1px solid #d2d2d2; + padding-block-end: .8rem; + margin-block-end: .8rem; + } + + ul { + padding-inline-start: 1em; + } + } + + footer { + margin-block-start: 2rem; + + .domain { + font-family: 'Courier New', Courier, monospace; + font-weight: 700; + } + } + } +} diff --git a/sass/style.scss b/sass/style.scss index 7dd3f92308..941faa6672 100644 --- a/sass/style.scss +++ b/sass/style.scss @@ -20,3 +20,4 @@ @import '_try-matrix'; @import '_support'; @import '_howitworks'; +@import '_public-instances'; diff --git a/static/assets/close.svg b/static/assets/close.svg new file mode 100644 index 0000000000..89a24af9c8 --- /dev/null +++ b/static/assets/close.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/js/public-instances.js b/static/js/public-instances.js new file mode 100644 index 0000000000..9f7e038850 --- /dev/null +++ b/static/js/public-instances.js @@ -0,0 +1,45 @@ +import { AllOfFilter, AnyOfFilter, refreshCardsView } from "./projects.js"; + +document.addEventListener('DOMContentLoaded', (event) => { + + var filters = []; + let structureFilter = new AnyOfFilter("filter-structure", "all-instances", filters); + let signupFilter = new AnyOfFilter("filter-signup", "all-instances", filters); + let locationFilter = new AnyOfFilter("filter-location", "all-instances", filters); + let softwareFilter = new AnyOfFilter("filter-software", "all-instances", filters) + filters.push( + structureFilter, + signupFilter, + locationFilter, + softwareFilter + ); + refreshCardsView("all-instances", filters); + for (const filter of filters) { + filter.refreshActiveState(); + } + + const dialogOpeners = document.querySelectorAll("#all-instances > div > a"); + const overlay = document.getElementById("filters-overlay"); + for(var opener of dialogOpeners) { + const modal = document.getElementById(opener.id + "-modal"); + const closers = modal.getElementsByClassName("close-button"); + for(const closer of closers) { + closer.addEventListener('click', () => { + modal.classList.remove("display"); + overlay.classList.remove("display"); + }); + } + opener.addEventListener('click', () => { + modal.classList.add("display"); + overlay.classList.add("display"); + }); + overlay.addEventListener('click', () => { + modal.classList.remove("display"); + }); + document.addEventListener('keydown', (e) => { + if(e.key == "Escape") { + modal.classList.remove("display"); + } + }) + } +}) diff --git a/templates/macros/public_instances.html b/templates/macros/public_instances.html new file mode 100644 index 0000000000..dabac4b8ad --- /dev/null +++ b/templates/macros/public_instances.html @@ -0,0 +1,523 @@ +{% macro registration_label(type) %} +{% if type.conditional %} +Conditional +{% else %} +Open to all +{% endif %} +{% endmacro %} + +{% macro country_name(code) %} +{% if code | upper == "AD" %} +Andorra +{% elif code | upper == "AE" %} +United Arab Emirates +{% elif code | upper == "AF" %} +Afghanistan +{% elif code | upper == "AG" %} +Antigua and Barbuda +{% elif code | upper == "AI" %} +Anguilla +{% elif code | upper == "AL" %} +Albania +{% elif code | upper == "AM" %} +Armenia +{% elif code | upper == "AO" %} +Angola +{% elif code | upper == "AQ" %} +Antarctica +{% elif code | upper == "AR" %} +Argentina +{% elif code | upper == "AS" %} +American Samoa +{% elif code | upper == "AT" %} +Austria +{% elif code | upper == "AU" %} +Australia +{% elif code | upper == "AW" %} +Aruba +{% elif code | upper == "AZ" %} +Azerbaijan +{% elif code | upper == "BA" %} +Bosnia and Herzegovina +{% elif code | upper == "BB" %} +Barbados +{% elif code | upper == "BD" %} +Bangladesh +{% elif code | upper == "BE" %} +Belgium +{% elif code | upper == "BF" %} +Burkina Faso +{% elif code | upper == "BG" %} +Bulgaria +{% elif code | upper == "BH" %} +Bahrain +{% elif code | upper == "BI" %} +Burundi +{% elif code | upper == "BJ" %} +Benin +{% elif code | upper == "BL" %} +Saint Barthélemy +{% elif code | upper == "BM" %} +Bermuda +{% elif code | upper == "BN" %} +Brunei +{% elif code | upper == "BO" %} +Bolivia +{% elif code | upper == "BQ" %} +Caribbean Netherlands +{% elif code | upper == "BR" %} +Brazil +{% elif code | upper == "BS" %} +The Bahamas +{% elif code | upper == "BT" %} +Bhutan +{% elif code | upper == "BV" %} +Bouvet Island +{% elif code | upper == "BW" %} +Botswana +{% elif code | upper == "BY" %} +Belarus +{% elif code | upper == "BZ" %} +Belize +{% elif code | upper == "CA" %} +Canada +{% elif code | upper == "CC" %} +Cocos (Keeling) Islands +{% elif code | upper == "CD" %} +Democratic Republic of the Congo +{% elif code | upper == "CF" %} +Central African Republic +{% elif code | upper == "CG" %} +Republic of the Congo +{% elif code | upper == "CH" %} +Switzerland +{% elif code | upper == "CK" %} +Cook Islands +{% elif code | upper == "CL" %} +Chile +{% elif code | upper == "CM" %} +Cameroon +{% elif code | upper == "CN" %} +China +{% elif code | upper == "CO" %} +Colombia +{% elif code | upper == "CR" %} +Costa Rica +{% elif code | upper == "CU" %} +Cuba +{% elif code | upper == "CV" %} +Cape Verde +{% elif code | upper == "CW" %} +Curaçao +{% elif code | upper == "CX" %} +Christmas Island +{% elif code | upper == "CY" %} +Cyprus +{% elif code | upper == "CZ" %} +Czech Republic +{% elif code | upper == "DE" %} +Germany +{% elif code | upper == "DJ" %} +Djibouti +{% elif code | upper == "DK" %} +Denmark +{% elif code | upper == "DM" %} +Dominica +{% elif code | upper == "DO" %} +Dominican Republic +{% elif code | upper == "DZ" %} +Algeria +{% elif code | upper == "EC" %} +Ecuador +{% elif code | upper == "EE" %} +Estonia +{% elif code | upper == "EG" %} +Egypt +{% elif code | upper == "EH" %} +Western Sahara +{% elif code | upper == "ER" %} +Eritrea +{% elif code | upper == "ES" %} +Spain +{% elif code | upper == "ET" %} +Ethiopia +{% elif code | upper == "FI" %} +Finland +{% elif code | upper == "FJ" %} +Fiji +{% elif code | upper == "FK" %} +Falkland Islands +{% elif code | upper == "FM" %} +Federated States of Micronesia +{% elif code | upper == "FO" %} +Faroe Islands +{% elif code | upper == "FR" %} +France +{% elif code | upper == "GA" %} +Gabon +{% elif code | upper == "GB" %} +United Kingdom +{% elif code | upper == "GD" %} +Grenada +{% elif code | upper == "GE" %} +Georgia +{% elif code | upper == "GF" %} +French Guiana +{% elif code | upper == "GG" %} +Bailiwick of Guernsey +{% elif code | upper == "GH" %} +Ghana +{% elif code | upper == "GI" %} +Gibraltar +{% elif code | upper == "GL" %} +Greenland +{% elif code | upper == "GM" %} +Gambia +{% elif code | upper == "GN" %} +Guinea +{% elif code | upper == "GP" %} +Guadeloupe +{% elif code | upper == "GQ" %} +Equatorial Guinea +{% elif code | upper == "GR" %} +Greece +{% elif code | upper == "GS" %} +South Georgia and the South Sandwich Islands +{% elif code | upper == "GT" %} +Guatemala +{% elif code | upper == "GU" %} +Guam +{% elif code | upper == "GW" %} +Guinea-Bissau +{% elif code | upper == "GY" %} +Guyana +{% elif code | upper == "HK" %} +Hong Kong +{% elif code | upper == "HM" %} +Heard Island and McDonald Islands +{% elif code | upper == "HN" %} +Honduras +{% elif code | upper == "HR" %} +Croatia +{% elif code | upper == "HT" %} +Haiti +{% elif code | upper == "HU" %} +Hungary +{% elif code | upper == "ID" %} +Indonesia +{% elif code | upper == "IE" %} +Republic of Ireland +{% elif code | upper == "IL" %} +Israel +{% elif code | upper == "IM" %} +Isle of Man +{% elif code | upper == "IN" %} +India +{% elif code | upper == "IO" %} +British Indian Ocean Territory +{% elif code | upper == "IQ" %} +Iraq +{% elif code | upper == "IR" %} +Iran +{% elif code | upper == "IS" %} +Iceland +{% elif code | upper == "IT" %} +Italy +{% elif code | upper == "JE" %} +Jersey +{% elif code | upper == "JM" %} +Jamaica +{% elif code | upper == "JO" %} +Jordan +{% elif code | upper == "JP" %} +Japan +{% elif code | upper == "KE" %} +Kenya +{% elif code | upper == "KG" %} +Kyrgyzstan +{% elif code | upper == "KH" %} +Cambodia +{% elif code | upper == "KI" %} +Kiribati +{% elif code | upper == "KM" %} +Comoros +{% elif code | upper == "KN" %} +Saint Kitts and Nevis +{% elif code | upper == "KP" %} +North Korea +{% elif code | upper == "KR" %} +South Korea +{% elif code | upper == "KW" %} +Kuwait +{% elif code | upper == "KY" %} +Cayman Islands +{% elif code | upper == "KZ" %} +Kazakhstan +{% elif code | upper == "LA" %} +Laos +{% elif code | upper == "LB" %} +Lebanon +{% elif code | upper == "LC" %} +Saint Lucia +{% elif code | upper == "LI" %} +Liechtenstein +{% elif code | upper == "LK" %} +Sri Lanka +{% elif code | upper == "LR" %} +Liberia +{% elif code | upper == "LS" %} +Lesotho +{% elif code | upper == "LT" %} +Lithuania +{% elif code | upper == "LU" %} +Luxembourg +{% elif code | upper == "LV" %} +Latvia +{% elif code | upper == "LY" %} +Libya +{% elif code | upper == "MA" %} +Morocco +{% elif code | upper == "MC" %} +Monaco +{% elif code | upper == "MD" %} +Moldova +{% elif code | upper == "ME" %} +Montenegro +{% elif code | upper == "MF" %} +Collectivity of Saint Martin +{% elif code | upper == "MG" %} +Madagascar +{% elif code | upper == "MH" %} +Marshall Islands +{% elif code | upper == "MK" %} +North Macedonia +{% elif code | upper == "ML" %} +Mali +{% elif code | upper == "MM" %} +Myanmar +{% elif code | upper == "MN" %} +Mongolia +{% elif code | upper == "MO" %} +Macau +{% elif code | upper == "MP" %} +Northern Mariana Islands +{% elif code | upper == "MQ" %} +Martinique +{% elif code | upper == "MR" %} +Mauritania +{% elif code | upper == "MS" %} +Montserrat +{% elif code | upper == "MT" %} +Malta +{% elif code | upper == "MU" %} +Mauritius +{% elif code | upper == "MV" %} +Maldives +{% elif code | upper == "MW" %} +Malawi +{% elif code | upper == "MX" %} +Mexico +{% elif code | upper == "MY" %} +Malaysia +{% elif code | upper == "MZ" %} +Mozambique +{% elif code | upper == "NA" %} +Namibia +{% elif code | upper == "NC" %} +New Caledonia +{% elif code | upper == "NE" %} +Niger +{% elif code | upper == "NF" %} +Norfolk Island +{% elif code | upper == "NG" %} +Nigeria +{% elif code | upper == "NI" %} +Nicaragua +{% elif code | upper == "NL" %} +Kingdom of the Netherlands +{% elif code | upper == "NO" %} +Norway +{% elif code | upper == "NP" %} +Nepal +{% elif code | upper == "NR" %} +Nauru +{% elif code | upper == "NU" %} +Niue +{% elif code | upper == "NZ" %} +New Zealand +{% elif code | upper == "OM" %} +Oman +{% elif code | upper == "PA" %} +Panama +{% elif code | upper == "PE" %} +Peru +{% elif code | upper == "PF" %} +French Polynesia +{% elif code | upper == "PG" %} +Papua New Guinea +{% elif code | upper == "PH" %} +Philippines +{% elif code | upper == "PK" %} +Pakistan +{% elif code | upper == "PL" %} +Poland +{% elif code | upper == "PM" %} +Saint Pierre and Miquelon +{% elif code | upper == "PN" %} +Pitcairn Islands +{% elif code | upper == "PR" %} +Puerto Rico +{% elif code | upper == "PT" %} +Portugal +{% elif code | upper == "PW" %} +Palau +{% elif code | upper == "PY" %} +Paraguay +{% elif code | upper == "QA" %} +Qatar +{% elif code | upper == "RO" %} +Romania +{% elif code | upper == "RS" %} +Serbia +{% elif code | upper == "RU" %} +Russia +{% elif code | upper == "RW" %} +Rwanda +{% elif code | upper == "SA" %} +Saudi Arabia +{% elif code | upper == "SB" %} +Solomon Islands +{% elif code | upper == "SC" %} +Seychelles +{% elif code | upper == "SD" %} +Sudan +{% elif code | upper == "SE" %} +Sweden +{% elif code | upper == "SG" %} +Singapore +{% elif code | upper == "SH" %} +Saint Helena, Ascension and Tristan da Cunha +{% elif code | upper == "SI" %} +Slovenia +{% elif code | upper == "SJ" %} +Svalbard and Jan Mayen +{% elif code | upper == "SK" %} +Slovakia +{% elif code | upper == "SL" %} +Sierra Leone +{% elif code | upper == "SM" %} +San Marino +{% elif code | upper == "SN" %} +Senegal +{% elif code | upper == "SO" %} +Somalia +{% elif code | upper == "SR" %} +Suriname +{% elif code | upper == "SS" %} +South Sudan +{% elif code | upper == "ST" %} +São Tomé and Príncipe +{% elif code | upper == "SV" %} +El Salvador +{% elif code | upper == "SX" %} +Sint Maarten +{% elif code | upper == "SY" %} +Syria +{% elif code | upper == "SZ" %} +Eswatini +{% elif code | upper == "TC" %} +Turks and Caicos Islands +{% elif code | upper == "TD" %} +Chad +{% elif code | upper == "TF" %} +French Southern and Antarctic Lands +{% elif code | upper == "TG" %} +Togo +{% elif code | upper == "TH" %} +Thailand +{% elif code | upper == "TJ" %} +Tajikistan +{% elif code | upper == "TK" %} +Tokelau +{% elif code | upper == "TL" %} +East Timor +{% elif code | upper == "TM" %} +Turkmenistan +{% elif code | upper == "TN" %} +Tunisia +{% elif code | upper == "TO" %} +Tonga +{% elif code | upper == "TR" %} +Türkiye +{% elif code | upper == "TT" %} +Trinidad and Tobago +{% elif code | upper == "TV" %} +Tuvalu +{% elif code | upper == "TW" %} +Taiwan +{% elif code | upper == "TZ" %} +Tanzania +{% elif code | upper == "UA" %} +Ukraine +{% elif code | upper == "UG" %} +Uganda +{% elif code | upper == "UM" %} +United States Minor Outlying Islands +{% elif code | upper == "US" %} +United States +{% elif code | upper == "UY" %} +Uruguay +{% elif code | upper == "UZ" %} +Uzbekistan +{% elif code | upper == "VA" %} +Vatican City +{% elif code | upper == "VC" %} +Saint Vincent and the Grenadines +{% elif code | upper == "VE" %} +Venezuela +{% elif code | upper == "VG" %} +British Virgin Islands +{% elif code | upper == "VI" %} +United States Virgin Islands +{% elif code | upper == "VN" %} +Vietnam +{% elif code | upper == "VU" %} +Vanuatu +{% elif code | upper == "WF" %} +Wallis and Futuna +{% elif code | upper == "WS" %} +Samoa +{% elif code | upper == "YE" %} +Yemen +{% elif code | upper == "YT" %} +Mayotte +{% elif code | upper == "ZA" %} +South Africa +{% elif code | upper == "ZM" %} +Zambia +{% elif code | upper == "ZW" %} +Zimbabwe +{% endif %} +{% endmacro %} + +{% macro structure_label(type) %} +{% if type == "individual" %} +Individual +{% elif type == "non-profit" %} +Non-profit +{% elif type == "paid-support" %} +Paid +{% endif %} +{% endmacro %} + +{% macro classes(instance) %} +{% set software_version = instance.software ~ " " ~ instance.version %} +location-{{ instance.location | lower }} +{%if instance.signup.restriction %} +signup-conditional +{% else %} +signup-unfiltered +{% endif %} +structure-{{ instance.structure | lower }} +software-{{ software_version | slugify }} +{% endmacro %} diff --git a/templates/public-instances.html b/templates/public-instances.html new file mode 100644 index 0000000000..358b5e49ed --- /dev/null +++ b/templates/public-instances.html @@ -0,0 +1,183 @@ +{% extends "section.html" %} +{% import "macros/public_instances.html" as instanceutils %} +{% block head_extra %} + + +{% endblock head_extra %} +{% block content %} + + +
+ {% set instances_data = load_data(path="/content/public-instances/instances.toml") %} + + {% set instances = instances_data.instances %} + {% set software = [] %} + {% set locations = [] %} + {% for instance in instances %} + {% set_global software = software | concat(with=instance.software ~ " " ~ instance.version) %} + {% set_global locations = locations | concat(with=instance.location) %} + {% endfor %} + {% set_global software = software | unique | sort %} + {% set_global locations = locations | unique | sort %} + +
+
All servers ({{ section.pages | length }})
+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+ +
+
+ + +
+
+ + +
+ +
+
+
+ +
+ {% for location in locations %} +
+ + +
+ {% endfor %} + +
+
+
+ +
+ {% for software_version in software %} +
+ + +
+ {% endfor %} + +
+
+
+
+ +
+
+ {% for instance in instances %} +
+ +
+ {{ instance.title | truncate(length=1, end="") }} +
+

{{ instance.title }}

+

{{ instance.description | safe }}

+
    +
  • {{ instanceutils::country_name(code=instance.location) }}
  • +
  • {{ instanceutils::registration_label(type=instance.signup) }}
  • +
  • {{ instanceutils::structure_label(type=instance.structure) }}
  • +
  • {{ instance.software | capitalize }} {{ instance.version }}
  • +
+
+
+ {% endfor %} +
+ {% for instance in instances %} +
+ +
+
+
+ {{ instance.title | truncate(length=1, end="") }} +
+

{{ instance.title }}

+
    +
  • {{ instanceutils::country_name(code=instance.location) }}
  • +
  • {{ instanceutils::structure_label(type=instance.structure) }}
  • +
+
+

{{ instance.description }}

+
+
+
+

Details

+
    +
  • Hosted by {{ instance.hoster }}
  • +
  • Located in {{ instanceutils::country_name(code=instance.location) }}
  • +
  • Created on {{ instance.creation_date | date(format="%e %B %Y") }}
  • +
+
+
+

Join information

+
    + {% if instance.signup.requires_email == true %} +
  • Requires email verification
  • + {% else %} +
  • Doesn't require email verification
  • + {% endif %} + {% if instance.signup.requires_captcha == true %} +
  • Requires captcha
  • + {% else %} +
  • Doesn't require captcha
  • + {% endif %} + {% if instance.privacy_policy %} +
  • Privacy policy
  • + {% else %} +
  • No privacy policy
  • + {% endif %} + {% if instance.terms_of_service %} +
  • Terms of service
  • + {% else %} +
  • No terms of service
  • + {% endif %} +
+
+
+ +
+ {% endfor %} +
+{% endblock content %}