From 66f3989c23f742763f8bf12303542b8dd72dc17f Mon Sep 17 00:00:00 2001 From: Tomislav R Date: Mon, 16 May 2022 11:08:14 +0200 Subject: [PATCH 01/60] WIP removing ipv6onlyhosting.{net,ch} references --- digitalglarus/locale/de/LC_MESSAGES/django.po | 1165 +++++++---------- dynamicweb/settings/base.py | 2 - dynamicweb/settings/prod.py | 2 - templates/gdpr/gdpr_banner.html | 2 - 4 files changed, 508 insertions(+), 663 deletions(-) diff --git a/digitalglarus/locale/de/LC_MESSAGES/django.po b/digitalglarus/locale/de/LC_MESSAGES/django.po index ec96f5dc..d5a50d71 100644 --- a/digitalglarus/locale/de/LC_MESSAGES/django.po +++ b/digitalglarus/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-01-31 23:53+0000\n" +"POT-Creation-Date: 2022-05-16 08:56+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,39 +18,6 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -msgid "Posted on" -msgstr "Veröffentlicht am" - -msgid "Articles by" -msgstr "Artikel vom" - -msgid "Archive" -msgstr "Archiv" - -msgid "Tag" -msgstr "" - -msgid "Category" -msgstr "Kategorie" - -msgid "No article found." -msgstr "Keine Artikel gefunden" - -msgid "Back" -msgstr "Zurück" - -msgid "Newer Posts" -msgstr "Neuere Einträge" - -msgid "Older Posts" -msgstr "Ältere Einträge" - -msgid "read more" -msgstr "weiterlesen" - -msgid "by" -msgstr "von" - msgid "Digital Glarus Gallery" msgstr "" @@ -69,9 +36,27 @@ msgstr "Postleitzahl" msgid "Country" msgstr "Land" +msgid "VAT Number" +msgstr "" + msgid "You haven been logged out" msgstr "Sie wurden abgemeldet" +msgid "Posted on" +msgstr "Veröffentlicht am" + +msgid "read more" +msgstr "weiterlesen" + +msgid "by" +msgstr "von" + +msgid "No article found." +msgstr "Keine Artikel gefunden" + +msgid "Back" +msgstr "Zurück" + msgid "previous" msgstr "vorherige" @@ -164,640 +149,506 @@ msgstr "befurworter/?$" msgid "Message Successfully Sent" msgstr "" -msgid "US English" -msgstr "" +#~ msgid "Articles by" +#~ msgstr "Artikel vom" -msgid "German" -msgstr "" +#~ msgid "Archive" +#~ msgstr "Archiv" -msgid "Content" -msgstr "" +#~ msgid "Category" +#~ msgstr "Kategorie" -msgid "default" -msgstr "" +#~ msgid "Newer Posts" +#~ msgstr "Neuere Einträge" -msgid "2 Column" -msgstr "" - -msgid "3 Column" -msgstr "" - -msgid "DG.About" -msgstr "" +#~ msgid "Older Posts" +#~ msgstr "Ältere Einträge" #, fuzzy -#| msgid "contact/?$" -msgid "DG.Contact" -msgstr "kontakt/?$" +#~| msgid "contact/?$" +#~ msgid "DG.Contact" +#~ msgstr "kontakt/?$" -msgid "DG.Home" -msgstr "" +#~ msgid "Amount" +#~ msgstr "Betrag" -msgid "DG.CoWork" -msgstr "" +#~ msgid "" +#~ "This site uses cookies for analytics. By continuing to\n" +#~ " browse this site, you agree to use this." +#~ msgstr "" +#~ "Diese Website verwendet Cookies für Analysezwecke. Mit dem weiterem " +#~ "Besuch dieser Website erklärst Du Dich damit einverstanden, diese zu " +#~ "nutzen." -msgid "DG.OneColumn" -msgstr "" +#~ msgid "Learn more" +#~ msgstr "Lerne mehr" -msgid "Blog" -msgstr "" +#~ msgid "Privacy policy" +#~ msgstr "Datenschutz-Bestimmungen" -msgid "Data Center Light" -msgstr "" - -msgid "Glasfaser" -msgstr "" - -msgid "ungleich" -msgstr "" - -msgid "English" -msgstr "" - -msgid "Deutsch" -msgstr "" - -msgid "Datacenterlight Navbar" -msgstr "" - -msgid "Datacenterlight Footer" -msgstr "" - -msgid "Datacenterlight Calculator" -msgstr "" - -msgid "Amount" -msgstr "Betrag" - -msgid "My Donations" -msgstr "" - -msgid "Set your new password" -msgstr "" - -msgid "Reset" -msgstr "" - -msgid "Already have an account ?" -msgstr "" - -msgid "Log in" -msgstr "" - -msgid "Invoice" -msgstr "" - -msgid "Donation #" -msgstr "" - -msgid "Billing Address:" -msgstr "" - -msgid "Date:" -msgstr "" - -msgid "Payment Method:" -msgstr "" - -msgid "Donation summary" -msgstr "" - -msgid "Donation" -msgstr "" - -msgid "Total" -msgstr "" - -msgid "Finish Configuration" -msgstr "" - -msgid "" -"Thanks for you donation, you can cancel your monthly donation at any time " -"going to profile > subscription " -msgstr "" - -msgid "View Donations" -msgstr "" - -msgid "Cancel Donation" -msgstr "" - -msgid "Donate" -msgstr "" - -msgid "Donations Made" -msgstr "" - -msgid "Date" -msgstr "" - -msgid "View Detail" -msgstr "" - -msgid "Reanude Donation" -msgstr "" - -#, python-format -msgid "" -"You're receiving this email because you requested a password reset for your " -"user account at %(site_name)s." -msgstr "" - -msgid "Please go to the following page and choose a new password:" -msgstr "" - -msgid "Thanks for using our site!" -msgstr "" - -#, python-format -msgid "The %(site_name)s team" -msgstr "" - -msgid "Log in " -msgstr "" - -msgid "Login" -msgstr "" - -msgid "Don't have an account yet ? " -msgstr "" - -msgid "Sign up" -msgstr "" - -msgid "Forgot your password ? " -msgstr "" - -msgid "Reset your password" -msgstr "" - -msgid "DG.Detail" -msgstr "" - -msgid "" -"This site uses cookies for analytics. By continuing to\n" -" browse this site, you agree to use this." -msgstr "" -"Diese Website verwendet Cookies für Analysezwecke. Mit dem weiterem Besuch " -"dieser Website erklärst Du Dich damit einverstanden, diese zu nutzen." - -msgid "Learn more" -msgstr "Lerne mehr" - -msgid "OK" -msgstr "" - -msgid "Privacy policy" -msgstr "Datenschutz-Bestimmungen" - -msgid "" -"\n" -" 1. Responsibility and scope
\n" -"
\n" -" Responsible in regards to EU General Data Protection\n" -" Regulation (\"GDPR\") and other applicable data " -"protection\n" -" laws:
\n" -"
\n" -" ungleich glarus ag
\n" -" Bahnhofstrasse 1
\n" -" 8783 Linthal (CH)
\n" -" Tel.: +41 55 505 6266
\n" -" E-Mail: info@ungleich.ch
\n" -"
\n" -" This privacy statement applies to the web content of\n" -" ungleich glarus ag, available at the
\n" -" following domains:
\n" -"
\n" -" ungleich.ch
\n" -" datacenterlight.ch
\n" -" devuanhosting.com
\n" -" devuanhosting.ch
\n" -" digitalglarus.ch
\n" -" hack4lgarus.ch
\n" -" ipv6onlyhosting.com
\n" -" ipv6onlyhosting.ch
\n" -" ipv6onlyhosting.net
\n" -" django-hosting.ch
\n" -" rails-hosting.ch
\n" -" node-hosting.ch
\n" -" blog.ungleich.ch
\n" -"
\n" -" The Data Privacy Officer:
\n" -"
\n" -" Sanghee Kim
\n" -" ungleich glarus ag
\n" -" Bahnhofstrasse 1
\n" -" 8783 Linthal (CH)
\n" -" E-Mail: sanghee.kim@ungleich.ch
\n" -"
\n" -"
\n" -" 2. General
\n" -"
\n" -" User data is personal data which is necessary to " -"establish\n" -" or change the contractual relations\n" -" between ungleich glarus ag (\"us\") and you. This " -"includes\n" -" among other things for example the\n" -" name, the address, the date of birth, the e-mail address " -"or\n" -" the IP address. We save and use\n" -" your personal data only for the processing of your " -"orders\n" -" or for getting in contact with you.
\n" -"
\n" -"
\n" -" 3. Processing of personal data
\n" -"
\n" -" When you call one of our websites we collect your IP\n" -" address. When you register an account with us your " -"contact\n" -" data will be stored. When you order products on our\n" -" platform we also collect among others your address and " -"your\n" -" payment details.
\n" -"
\n" -" I. Registration data
\n" -"
\n" -" In the process of registration we need to collect some " -"of\n" -" your personal data. For example we collect your name, " -"your\n" -" address, your telephone number, your e-mail address and\n" -" your payment details to process orders. We do not " -"collect\n" -" your payment details such as credit card number, " -"expiration\n" -" date or the cvv code when you pay with credit card. You\n" -" expose those data directly to the respective payment\n" -" processor. Payments with credit card are processed by\n" -" Stripe Payments Europe Ltd. (\"Stripe\").
\n" -"
\n" -"
\n" -" II. Server log files
\n" -"
\n" -" When you call one of our websites we automatically save\n" -" traffic data. Normally the IP address, the type and " -"version\n" -" of your browser, the time and the website that lead to " -"our\n" -" website (\"Referer\") will be saved. Your IP address is\n" -" collected anonymously so that we cannot match it with " -"your\n" -" person. The collection of those data is necessary to\n" -" provide our websites and services, according to Art. 6 " -"par.\n" -" 1 lit. f GDPR.
\n" -"
\n" -"
\n" -" 4. Storage durations
\n" -"
\n" -" Your data will be deleted immediately, as soon as it " -"isn't\n" -" relevant anymore for any contract between you and us. " -"In\n" -" some cases it could be necessary to store your data\n" -" further, to comply with our contractual or other legal\n" -" obligatons.
\n" -"
\n" -"
\n" -" 5. Disclosure of your personal data
\n" -"
\n" -" We don't disclose your personal data to third parties,\n" -" except:
\n" -"
\n" -" a) You grant us your explicit permission according to " -"Art.\n" -" 6 par. 1 S. 1 lit. a GDPR.
\n" -"
\n" -" b) The disclosure of your data is legal and it is " -"necessary\n" -" to comply with our contractual or other legal " -"obligations,\n" -" according to Art. 6 par. 1 S. 1 lit b GDPR.
\n" -"
\n" -" c) There is a law or legal obligation to disclose your " -"data\n" -" or the disclosure is necessary for the performance of a\n" -" task carried out in the public interest or in the " -"exercise\n" -" of an official authority according to Art. 6 par. 1 S. " -"1\n" -" lit. c GDPR.
\n" -"
\n" -" d) The disclosure of your data is necessary for the\n" -" purposes of the legitimate interests pursued by us or by " -"a\n" -" third party, except where such interests are overridden " -"by\n" -" the interests or your fundamental right according to " -"Art.\n" -" 6. par. 1 S. 1 lit. f GDPR.
\n" -"
\n" -"
\n" -" 6. Cookies, Google Analytics, Twitter
\n" -"
\n" -" We use Cookies. When you visit one of our websites,\n" -" information is stored on your terminal device in the " -"form\n" -" of a \"cookie\". Cookies are small text files that are " -"stored\n" -" on your terminal device by your browser. You can opt-out " -"of\n" -" the storage of cookies in the settings of your\n" -" browser-software, but however, in this case you might " -"not\n" -" be able to fully use all functions and services on our\n" -" website.
\n" -"
\n" -" We use Google Analytics, a service provided by Google " -"Inc.,\n" -" 1600 Amphitheatre Parkway, Mountainview, CA 94043, USA\n" -" (\"Google\"). Google uses Cookies. Google will use " -"these\n" -" cookies on our behalf to analyse how you use our " -"websites\n" -" and to generate reports about the activities on our\n" -" websites. The information collected by those cookies " -"will\n" -" be transmitted to a Google server in the United States " -"of\n" -" America. We have Google's IP anonymization activated, " -"so\n" -" your IP address will be shortened before transmitting " -"to\n" -" Google. Only in exceptional cases the full IP address " -"will\n" -" be transmitted and then shortened afterwards.
\n" -"
\n" -" You may opt out from thecollection of these cookies by\n" -" downloading and installing a browser plugin available " -"at\n" -" the following link:
\n" -"
\n" -" http://tools.google.com/dlpage/gaoptout
\n" -"
\n" -" You may find further information about the processing " -"of\n" -" your personal data at the following links:
\n" -"
\n" -" https://policies.google.com/technologies/ads
\n" -"
\n" -" https://www.privacyshield.gov/" -"participant?id=a2zt000000001L5AAI&status=Active
\n" -"
\n" -" https://adssettings.google.com/authenticated
\n" -"
\n" -" The collected personal data will be deleted or " -"anonymized\n" -" after 14 months according to Art. 6 par. 1 lit. f\n" -" GDPR.
\n" -"
\n" -" Our websites use several functions from the social " -"network\n" -" Twitter, a service provided by Twitter Inc., 1355 " -"Market\n" -" Street, Suite 900, San Francisco, CA 94103, USA. We may\n" -" embed content of Twitter in our websites, such as " -"photos,\n" -" videos, texts or buttons. If you are registered with\n" -" Twitter, they may combine your use of these " -"functionalities\n" -" on our websites with your Twitter account. You may find\n" -" further information at https://twitter.com/de/privacy." -"
\n" -"
\n" -"
\n" -" 7. Your rights concerning your personal\n" -" data
\n" -"
\n" -" Under applicable GDPR you may have the right to:
\n" -"
\n" -" a) Obtain confirmation as to whether or not personal " -"data\n" -" concerning you are being processed, and where that is " -"the\n" -" case, access to the personal data, according to Art. 15\n" -" GDPR.
\n" -"
\n" -" b) Obtain the rectification of false or inaccurate data\n" -" concerning you, according to Art. 15, Art. 16 GDPR.
\n" -"
\n" -" c) Obtain the deletion of your personal data, according " -"to\n" -" Art. 17 GDPR.
\n" -"
\n" -" d) Obtain the restriction of processing your personal " -"data,\n" -" according to Art. 18 GDPR.
\n" -"
\n" -" e) Obtain a digital copy of your personal data processed " -"by\n" -" us, according to Art. 20 GDPR.
\n" -"
\n" -" f) Revoke a granted permission regarding your personal " -"data\n" -" at any time, according to Art. 7 par. 3 GDPR.
\n" -"
\n" -" g) Complain at a data protection authority, according " -"to\n" -" Art. 77 GDPR.
\n" -"
\n" -"
\n" -"
\n" -" 8. Hyperlinks / Disclaimer
\n" -"
\n" -" This privacy policy applies only to our websites and not " -"to\n" -" other websites or applications operated by third " -"parties.\n" -" We may provide links to other websites but we are not\n" -" responsible for the privacy practices of such other\n" -" websites.
\n" -"
\n" -"
\n" -" " -msgstr "" -"\n" -"1. Verantwortung und Geltungsbereich

Verantwortlich im Sinne der EU-Datenschutzgrundverordnung („DSGVO“) und " -"sonstiger datenschutzrechtlicher Bestimmungen ist:

ungleich glarus " -"ag
Bahnhofstrasse 1
8783 Linthal (CH)
Tel.: +41 55 505 6266
E-Mail: info@ungleich.ch

Diese Datenschutzerklärung gilt für das " -"Internetangebot der ungleich glarus ag, welches unter den nachfolgenden " -"Domains erreichbar ist:

ungleich.ch
datacenterlight.ch
devuanhosting.com
devuanhosting.ch
digitalglarus.ch
hack4lgarus." -"ch
ipv6onlyhosting.com
ipv6onlyhosting.ch
ipv6onlyhosting.net
django-hosting.ch
rails-hosting.ch
node-hosting.ch
blog." -"ungleich.ch

Der Datenschutzbeauftragte des Verantwortlichen ist:

Sanghee Kim
ungleich glarus ag
Bahnhofstrasse 1
8783 " -"Linthal (CH)
E-Mail: sanghee." -"kim@ungleich.ch


2. Grundsätzliches

Bei personenbezogenen Daten handelt es sich um alle Informationen, die " -"sich auf eine identifizierte oder identifizierbare natürliche Person " -"beziehen. Hierzu gehört zum Beispiel dein Name, deine Anschrift, dein " -"Geburtsdatum, deine E-Mail-Adresse oder deine IP-Adresse. Wir speichern und " -"verwenden deine personenbezogenen Daten ausschließlich für die Bearbeitung " -"deiner Aufträge und für die Kontaktaufnahme mit dir.


3. Verarbeitung deiner personenbezogenen Daten

Bei jedem Aufruf einer unserer Internetseiten wird u. a. deine IP-Adresse " -"gespeichert. Wenn du dich bei uns registrierst, werden deine Kontaktdaten " -"gespeichert. Wenn du Aufträge an uns richtest oder Produkte bei uns " -"bestellst, werden darüber hinaus auch deine Anschrift und deine
Zahlungsdaten gespeichert.

I. Registrierungsdaten

Im Rahmen der Registrierung müssen wir einige " -"personenbezogene Daten von dir erheben und verarbeiten. Beispielsweise " -"benötigen wir deinen Namen, deine Anschrift, deine Telefonnummer, deine E-" -"Mail-Adresse und deine Zahlungsdaten um deine Aufträge zu verarbeiten.
Bei der Zahlung mittels Kreditkarte erfassen und speichern wir keine " -"Zahlungsverkehrsinformationen wie Kreditkartennummern, das Ablaufdatum oder " -"die Prüfziffer. Diese gibst du ausschließlich direkt dem entsprechenden " -"Zahlungsdienstleister bekannt. Bei der Bezahlung mit Kreditkarte erfolgt die " -"Abwicklung der Bezahlung durch einen externen Dienstleister.
Für die " -"Kreditkartenzahlung werden deine Angaben direkt vom Diensteanbieter Stripe " -"Payments Europe Ltd. („Stripe“) verarbeitet.

II. " -"Serverlogdateien

Bei jedem Aufruf einer unserer " -"Internetseiten speichern wir automatisch bestimmte Daten. Dazu gehören u. a. " -"deine IP-Adresse, Typ und Version des verwendeten Browsers, Uhrzeit, Datum " -"und die Webseite von der du auf unsere Seite gelangst (sog. „Referer“). " -"Deine IP-Adresse wird bei uns nur anonymisiert gespeichert, sodass ein " -"Personenbezug nicht mehr herstellbar ist. Die Erfassung der Daten zur " -"Bereitstellung unserer Internetseiten und die Speicherung der Daten in den " -"Server Logfiles ist für den Betrieb der Internetseite zwingend erforderlich " -"und dient damit der Wahrung eines berechtigten Interesses unseres " -"Unternehmens. Die Rechtsgrundlage für diese Verarbeitung ist Art. 6. Abs. 1 " -"lit. f DSGVO.


4. Speicherdauer

Sofern die verarbeiteten personenbezogenen Daten für die Durchführung eines " -"ggf.
geschlossenen Vertrages nicht mehr erforderlich sind, werden sie " -"umgehend gelöscht. Jedoch kann es auch nach Abschluss des Vertrags " -"erforderlich sein, personenbezogene Daten von dir zu speichern, um unseren " -"vertraglichen oder gesetzlichen Verpflichtungen nachzukommen.


5. Weitergabe von personenbezogenen Daten

Wir " -"geben deine personenbezogenen Daten grundsätzlich nicht an Dritte weiter, es " -"sei denn:

a) Du erteilst uns hierzu deine ausdrückliche " -"Einwilligung nach Art. 6 Abs. 1 S. 1 lit. a DSGVO.

b) Die " -"Weitergabe der Daten ist gesetzlich zulässig und nach Art. 6. Abs. 1 S. 1 " -"lit b DSGVO zur Erfüllung unserer vertraglichen Pflichten mit Ihnen " -"erforderlich.

c) Für die Weitergabe der Daten besteht nach Art. 6. " -"Abs. 1 S. 1 lit. c DSGVO eine gesetzliche Verpflichtung.

d) Die " -"Weitergabe der Daten ist nach Art. 6. Abs. 1 S. 1 lit. f DSGVO zur Wahrung " -"unserer berechtigten Interessen, sowie zur Geltendmachung, Ausübung oder " -"


6. Cookies, Google Analytics und Twitter

Wir " -"setzen auf unseren Internetseiten sog. „Cookies“ ein. Cookies sind kleine " -"Textdateien, die im Rahmen deines Besuchs einer unserer Internetseiten von " -"uns an den Browser deines Endgeräts gesendet und dort gespeichert werden. " -"Einige Funktionen unseres Angebots können ohne den Einsatz bestimmter " -"Cookies grundsätzlich aus technischen Gründen nicht angeboten werden. Du " -"kannst deinen Browser allerdings so konfigurieren, dass er nur noch " -"bestimmte oder auch gar keine Cookies mehr akzeptiert. Es kann jedoch " -"passieren, dass du dadurch möglicherweise nicht mehr alle Funktionen unserer " -"Internetseiten nutzen kannst.
Andere Cookies ermöglichen es uns hingegen " -"verschiedene Analysen deines Verhaltens oder etwa eine Verbindung zu deinen " -"sozialen Netzwerken aufzubauen. Mithilfe dieser Cookies können wir " -"beispielsweise unser Internetangebot für dich nutzerfreundlicher und " -"effektiver gestalten. Daraus folgt, dass wir auf Grundlage unserer " -"berechtigten Unternehmensinteressen (Optimierung und wirtschaftlicher " -"Betrieb unseres Internetangebots) den Werbeanalysedienst „Google Analytics“ " -"der Google Inc., 1600 Amphitheatre Parkway, Mountainview, CA 94043, " -"Vereinigte Staaten von Amerika („Google“) einsetzen. Google verwendet " -"Cookies. Die durch das Cookie erzeugten Informationen werden an einen Server " -"von Google in den Vereinigten Staaten von Amerika übertragen und dort " -"erhoben und gespeichert. Google nutzt dies Informationen in unserem Auftrag " -"dafür, die Nutzung unseres Internetangebots auszuwerten und Berichte über " -"die Aktivitäten auf unserem Onlineangebot uns gegenüber zu erbringen.
Dabei werden aus den verarbeiteten Daten anonymisierte bzw. pseudonyme " -"Nutzungsprofile einiger Nutzer erstellt. Diese Nutzungsprofile sind nicht " -"auf eine IP-Adresse oder einen spezifischen Nutzer zurückzuführen. Darüber " -"hinaus setzen wir Google Analytics nur mit IP-Anonymisierung ein. Das heißt, " -"dass die IP-Adresse von Google gekürzt wird. Nur in wenigen Ausnahmefällen " -"wird die vollständige IP-Adresse an Google übertragen und dort gekürzt. Du " -"kannst der Verarbeitung von deinen erfassten Daten durch die Installation " -"dieses Browserplugins widersprechen: http://tools.google.com/dlpage/gaoptout?hl=de

Weitere Informationen zur Nutzung der Daten durch Google und " -"weiterführende Widerspruchsmöglichkeiten erhältst du in der " -"Datenschutzerklärung von Google:

https://policies.google.com/technologies/ads

und auf den folgenden Webseiten:

https://" -"www.privacyshield.gov/participant?id=a2zt000000001L5AAI&status=Active

https://" -"adssettings.google.com/authenticated

Die personenbezogenen " -"Daten werden nach 14 Monaten gelöscht oder anonymisiert.
Rechtliche " -"Grundlage hierfür ist Art. 6 Abs. 1 lit. f DSGVO.

Innerhalb unseres " -"Onlineangebots können Funktionen und Inhalte des Dienstes Twitter " -"eingebunden werden. Twitter ist ein Dienst der Twitter Inc., 1355 Market " -"Street, Suite 900, San Francisco, CA 94103, Vereinigte Staaten von Amerika. " -"Hierzu können beispielsweise Inhalte wie Bilder, Videos oder Texte und " -"Schaltflächen gehören. Sofern du Mitglied der Plattform Twitter bist, kann " -"Twitter den Aufruf der Funktionalitäten deinem dortigen Profil zuordnen.
Weitere Informationen zum Datenschutz bei Twitter, findest du in der " -"Datenschutzerklärung von
Twitter unter https://twitter.com/de/privacy.



7. " -"Rechte des Betroffenen

Aus der DSGVO ergeben sich für dich " -"als Betroffener die folgenden Rechte:

a) Du kannst gem. Art. 15 " -"DSGVO Auskunft über deine von uns verarbeiteten personenbezogenen Daten " -"verlangen. Du kannst insbesondere Auskunft über den Zweck der Verarbeitung, " -"die Kategorien der erhobenen personenbezogenen Daten, die Kategorien von " -"Dritten, gegenüber denen deine Daten offengelegt werden und die " -"voraussichtliche Speicherdauer verlangen.

b) Du hast gem. Art. 15 " -"u. Art. 16 DSGVO ein Recht auf Berichtigung, Vervollständigung, Löschung und " -"die Bestimmung von Einschränkungen hinsichtlich der Verarbeitung deiner " -"personenbezogenen Daten.

c) Gemäß Art. 17 DSGVO kannst du von uns " -"die Löschung deiner bei uns gespeicherten personenbezogenen Daten verlangen, " -"soweit die Verarbeitung nicht zur Erfüllung unserer rechtlichen " -"Verpflichtungen, aus Gründen des öffentlichen Interesses oder zur " -"Geltendmachung, Ausübung oder Verteidigung von Rechtsansprüchen erforderlich " -"ist.

d) Gemäß Art. 18 DSGVO kannst du von uns die Einschränkung der " -"Verarbeitung deiner personenbezogenen Daten verlangen, soweit die " -"Richtigkeit der Daten von dir bestritten wird, die Verarbeitung " -"grundsätzlich unrechtmäßig ist oder die Löschung deiner
personenbezogenen Daten durch uns ablehnen, weil du diese zur " -"Geltendmachung, Ausübung oder Verteidigung von Rechtsansprüchen benötigst." -"

e) Gemäß Art. 20 DSGVO kannst du von uns verlangen, dass deine " -"personenbezogenen Daten, die du uns zur Verfügung gestellt hast, in einem " -"strukturierten, maschinenlesbaren und gängigen Format zu erhalten oder du " -"kannst die Übermittlung an eine andere Stelle verlangen.

f) Gemäß " -"Art. 7 Abs. 3 DSGVO kannst du deine erteilte Einwilligung gegenüber uns " -"jederzeit widerrufen. Dies hat zur Folge, dass wir die auf dieser " -"Einwilligung beruhende Datenverarbeitung für die Zukunft nicht mehr " -"fortführen dürfen.

g) Gemäß Art. 77 DSGVO steht dir das Recht zu, " -"dich bei einer Aufsichtsbehörde zu beschweren.


8. " -"Hyperlinks und Haftungsausschluss

Auf unseren " -"Internetseiten befinden sich sog. „Hyperlinks“, also Verbindungen bzw.
Weiterleitungen zu den Internetseiten Dritter. Bei Aktivierung dieser " -"Hyperlinks durch Anklicken, wirst du von unserer Internetseite direkt auf " -"die Internetseite eines Dritten weitergeleitet. Wir können keine " -"Verantwortung für den vertraulichen Umgang deiner Daten auf diesen Webseiten " -"Dritter übernehmen, da wir keinen Einfluss darauf haben, dass diese " -"Unternehmen die Datenschutzbestimmungen der DSGVO einhalten. Wir weisen dich " -"außerdem darauf hin, dass es aufgrund der Struktur des Internets möglich " -"ist, dass die Regelungen des Datenschutzes bzw. der DSGVO von anderen, " -"dritten Personen oder Institutionen die nicht innerhalb unseres " -"Verantwortungsbereichs liegen nicht beachtet werden, oder dass sich spontan, " -"kurzfristig schwerwiegende Sicherheitslücken in verbreiteten Standards und " -"technischen Protokollen auftun, die die Datenintegrität gefährden könnten." -"

\n" -" " - -msgid "Page Header" -msgstr "" - -#, python-format -msgid "No %(verbose_name)s found matching the query" -msgstr "" +#~ msgid "" +#~ "\n" +#~ " 1. Responsibility and scope
\n" +#~ "
\n" +#~ " Responsible in regards to EU General Data Protection\n" +#~ " Regulation (\"GDPR\") and other applicable data " +#~ "protection\n" +#~ " laws:
\n" +#~ "
\n" +#~ " ungleich glarus ag
\n" +#~ " Bahnhofstrasse 1
\n" +#~ " 8783 Linthal (CH)
\n" +#~ " Tel.: +41 55 505 6266
\n" +#~ " E-Mail: info@ungleich.ch
\n" +#~ "
\n" +#~ " This privacy statement applies to the web content of\n" +#~ " ungleich glarus ag, available at the
\n" +#~ " following domains:
\n" +#~ "
\n" +#~ " ungleich.ch
\n" +#~ " datacenterlight.ch
\n" +#~ " devuanhosting.com
\n" +#~ " devuanhosting.ch
\n" +#~ " digitalglarus.ch
\n" +#~ " hack4lgarus.ch
\n" +#~ " ipv6onlyhosting.com
\n" +#~ " ipv6onlyhosting.ch
\n" +#~ " ipv6onlyhosting.net
\n" +#~ " django-hosting.ch
\n" +#~ " rails-hosting.ch
\n" +#~ " node-hosting.ch
\n" +#~ " blog.ungleich.ch
\n" +#~ "
\n" +#~ " The Data Privacy Officer:
\n" +#~ "
\n" +#~ " Sanghee Kim
\n" +#~ " ungleich glarus ag
\n" +#~ " Bahnhofstrasse 1
\n" +#~ " 8783 Linthal (CH)
\n" +#~ " E-Mail: sanghee.kim@ungleich.ch
\n" +#~ "
\n" +#~ "
\n" +#~ " 2. General
\n" +#~ "
\n" +#~ " User data is personal data which is necessary to " +#~ "establish\n" +#~ " or change the contractual relations\n" +#~ " between ungleich glarus ag (\"us\") and you. This " +#~ "includes\n" +#~ " among other things for example the\n" +#~ " name, the address, the date of birth, the e-mail " +#~ "address or\n" +#~ " the IP address. We save and use\n" +#~ " your personal data only for the processing of your " +#~ "orders\n" +#~ " or for getting in contact with you.
\n" +#~ "
\n" +#~ "
\n" +#~ " 3. Processing of personal data
\n" +#~ "
\n" +#~ " When you call one of our websites we collect your IP\n" +#~ " address. When you register an account with us your " +#~ "contact\n" +#~ " data will be stored. When you order products on our\n" +#~ " platform we also collect among others your address " +#~ "and your\n" +#~ " payment details.
\n" +#~ "
\n" +#~ " I. Registration data
\n" +#~ "
\n" +#~ " In the process of registration we need to collect " +#~ "some of\n" +#~ " your personal data. For example we collect your name, " +#~ "your\n" +#~ " address, your telephone number, your e-mail address " +#~ "and\n" +#~ " your payment details to process orders. We do not " +#~ "collect\n" +#~ " your payment details such as credit card number, " +#~ "expiration\n" +#~ " date or the cvv code when you pay with credit card. " +#~ "You\n" +#~ " expose those data directly to the respective payment\n" +#~ " processor. Payments with credit card are processed " +#~ "by\n" +#~ " Stripe Payments Europe Ltd. (\"Stripe\").
\n" +#~ "
\n" +#~ "
\n" +#~ " II. Server log files
\n" +#~ "
\n" +#~ " When you call one of our websites we automatically " +#~ "save\n" +#~ " traffic data. Normally the IP address, the type and " +#~ "version\n" +#~ " of your browser, the time and the website that lead " +#~ "to our\n" +#~ " website (\"Referer\") will be saved. Your IP address " +#~ "is\n" +#~ " collected anonymously so that we cannot match it with " +#~ "your\n" +#~ " person. The collection of those data is necessary to\n" +#~ " provide our websites and services, according to Art. " +#~ "6 par.\n" +#~ " 1 lit. f GDPR.
\n" +#~ "
\n" +#~ "
\n" +#~ " 4. Storage durations
\n" +#~ "
\n" +#~ " Your data will be deleted immediately, as soon as it " +#~ "isn't\n" +#~ " relevant anymore for any contract between you and us. " +#~ "In\n" +#~ " some cases it could be necessary to store your data\n" +#~ " further, to comply with our contractual or other " +#~ "legal\n" +#~ " obligatons.
\n" +#~ "
\n" +#~ "
\n" +#~ " 5. Disclosure of your personal data
\n" +#~ "
\n" +#~ " We don't disclose your personal data to third " +#~ "parties,\n" +#~ " except:
\n" +#~ "
\n" +#~ " a) You grant us your explicit permission according to " +#~ "Art.\n" +#~ " 6 par. 1 S. 1 lit. a GDPR.
\n" +#~ "
\n" +#~ " b) The disclosure of your data is legal and it is " +#~ "necessary\n" +#~ " to comply with our contractual or other legal " +#~ "obligations,\n" +#~ " according to Art. 6 par. 1 S. 1 lit b GDPR.
\n" +#~ "
\n" +#~ " c) There is a law or legal obligation to disclose " +#~ "your data\n" +#~ " or the disclosure is necessary for the performance of " +#~ "a\n" +#~ " task carried out in the public interest or in the " +#~ "exercise\n" +#~ " of an official authority according to Art. 6 par. 1 " +#~ "S. 1\n" +#~ " lit. c GDPR.
\n" +#~ "
\n" +#~ " d) The disclosure of your data is necessary for the\n" +#~ " purposes of the legitimate interests pursued by us or " +#~ "by a\n" +#~ " third party, except where such interests are " +#~ "overridden by\n" +#~ " the interests or your fundamental right according to " +#~ "Art.\n" +#~ " 6. par. 1 S. 1 lit. f GDPR.
\n" +#~ "
\n" +#~ "
\n" +#~ " 6. Cookies, Google Analytics, Twitter
\n" +#~ "
\n" +#~ " We use Cookies. When you visit one of our websites,\n" +#~ " information is stored on your terminal device in the " +#~ "form\n" +#~ " of a \"cookie\". Cookies are small text files that " +#~ "are stored\n" +#~ " on your terminal device by your browser. You can opt-" +#~ "out of\n" +#~ " the storage of cookies in the settings of your\n" +#~ " browser-software, but however, in this case you might " +#~ "not\n" +#~ " be able to fully use all functions and services on " +#~ "our\n" +#~ " website.
\n" +#~ "
\n" +#~ " We use Google Analytics, a service provided by Google " +#~ "Inc.,\n" +#~ " 1600 Amphitheatre Parkway, Mountainview, CA 94043, " +#~ "USA\n" +#~ " (\"Google\"). Google uses Cookies. Google will use " +#~ "these\n" +#~ " cookies on our behalf to analyse how you use our " +#~ "websites\n" +#~ " and to generate reports about the activities on our\n" +#~ " websites. The information collected by those cookies " +#~ "will\n" +#~ " be transmitted to a Google server in the United " +#~ "States of\n" +#~ " America. We have Google's IP anonymization activated, " +#~ "so\n" +#~ " your IP address will be shortened before transmitting " +#~ "to\n" +#~ " Google. Only in exceptional cases the full IP address " +#~ "will\n" +#~ " be transmitted and then shortened afterwards.
\n" +#~ "
\n" +#~ " You may opt out from thecollection of these cookies " +#~ "by\n" +#~ " downloading and installing a browser plugin available " +#~ "at\n" +#~ " the following link:
\n" +#~ "
\n" +#~ " http://tools.google.com/dlpage/gaoptout
\n" +#~ "
\n" +#~ " You may find further information about the processing " +#~ "of\n" +#~ " your personal data at the following links:
\n" +#~ "
\n" +#~ " https://policies.google.com/technologies/ads
\n" +#~ "
\n" +#~ " https://www.privacyshield.gov/" +#~ "participant?id=a2zt000000001L5AAI&status=Active
\n" +#~ "
\n" +#~ " https://adssettings.google.com/authenticated
\n" +#~ "
\n" +#~ " The collected personal data will be deleted or " +#~ "anonymized\n" +#~ " after 14 months according to Art. 6 par. 1 lit. f\n" +#~ " GDPR.
\n" +#~ "
\n" +#~ " Our websites use several functions from the social " +#~ "network\n" +#~ " Twitter, a service provided by Twitter Inc., 1355 " +#~ "Market\n" +#~ " Street, Suite 900, San Francisco, CA 94103, USA. We " +#~ "may\n" +#~ " embed content of Twitter in our websites, such as " +#~ "photos,\n" +#~ " videos, texts or buttons. If you are registered with\n" +#~ " Twitter, they may combine your use of these " +#~ "functionalities\n" +#~ " on our websites with your Twitter account. You may " +#~ "find\n" +#~ " further information at https://twitter.com/de/privacy." +#~ "
\n" +#~ "
\n" +#~ "
\n" +#~ " 7. Your rights concerning your personal\n" +#~ " data
\n" +#~ "
\n" +#~ " Under applicable GDPR you may have the right to:
\n" +#~ "
\n" +#~ " a) Obtain confirmation as to whether or not personal " +#~ "data\n" +#~ " concerning you are being processed, and where that is " +#~ "the\n" +#~ " case, access to the personal data, according to Art. " +#~ "15\n" +#~ " GDPR.
\n" +#~ "
\n" +#~ " b) Obtain the rectification of false or inaccurate " +#~ "data\n" +#~ " concerning you, according to Art. 15, Art. 16 GDPR." +#~ "
\n" +#~ "
\n" +#~ " c) Obtain the deletion of your personal data, " +#~ "according to\n" +#~ " Art. 17 GDPR.
\n" +#~ "
\n" +#~ " d) Obtain the restriction of processing your personal " +#~ "data,\n" +#~ " according to Art. 18 GDPR.
\n" +#~ "
\n" +#~ " e) Obtain a digital copy of your personal data " +#~ "processed by\n" +#~ " us, according to Art. 20 GDPR.
\n" +#~ "
\n" +#~ " f) Revoke a granted permission regarding your " +#~ "personal data\n" +#~ " at any time, according to Art. 7 par. 3 GDPR.
\n" +#~ "
\n" +#~ " g) Complain at a data protection authority, according " +#~ "to\n" +#~ " Art. 77 GDPR.
\n" +#~ "
\n" +#~ "
\n" +#~ "
\n" +#~ " 8. Hyperlinks / Disclaimer
\n" +#~ "
\n" +#~ " This privacy policy applies only to our websites and " +#~ "not to\n" +#~ " other websites or applications operated by third " +#~ "parties.\n" +#~ " We may provide links to other websites but we are " +#~ "not\n" +#~ " responsible for the privacy practices of such other\n" +#~ " websites.
\n" +#~ "
\n" +#~ "
\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ "1. Verantwortung und Geltungsbereich

Verantwortlich im Sinne der EU-Datenschutzgrundverordnung („DSGVO“) und " +#~ "sonstiger datenschutzrechtlicher Bestimmungen ist:

ungleich " +#~ "glarus ag
Bahnhofstrasse 1
8783 Linthal (CH)
Tel.: +41 55 505 " +#~ "6266
E-Mail: info@ungleich.ch

Diese Datenschutzerklärung " +#~ "gilt für das Internetangebot der ungleich glarus ag, welches unter den " +#~ "nachfolgenden Domains erreichbar ist:

ungleich.ch
datacenterlight.ch
devuanhosting.com
devuanhosting.ch
digitalglarus.ch
hack4lgarus.ch
ipv6onlyhosting.com
ipv6onlyhosting.ch
ipv6onlyhosting.net
django-hosting.ch
rails-hosting.ch
node-hosting.ch
blog.ungleich.ch

Der " +#~ "Datenschutzbeauftragte des Verantwortlichen ist:

Sanghee Kim
ungleich glarus ag
Bahnhofstrasse 1
8783 Linthal (CH)
E-" +#~ "Mail: sanghee.kim@ungleich.ch


2. Grundsätzliches

Bei " +#~ "personenbezogenen Daten handelt es sich um alle Informationen, die sich " +#~ "auf eine identifizierte oder identifizierbare natürliche Person beziehen. " +#~ "Hierzu gehört zum Beispiel dein Name, deine Anschrift, dein Geburtsdatum, " +#~ "deine E-Mail-Adresse oder deine IP-Adresse. Wir speichern und verwenden " +#~ "deine personenbezogenen Daten ausschließlich für die Bearbeitung deiner " +#~ "Aufträge und für die Kontaktaufnahme mit dir.


3. " +#~ "Verarbeitung deiner personenbezogenen Daten

Bei jedem " +#~ "Aufruf einer unserer Internetseiten wird u. a. deine IP-Adresse " +#~ "gespeichert. Wenn du dich bei uns registrierst, werden deine Kontaktdaten " +#~ "gespeichert. Wenn du Aufträge an uns richtest oder Produkte bei uns " +#~ "bestellst, werden darüber hinaus auch deine Anschrift und deine
Zahlungsdaten gespeichert.

I. Registrierungsdaten

Im Rahmen der Registrierung müssen wir einige " +#~ "personenbezogene Daten von dir erheben und verarbeiten. Beispielsweise " +#~ "benötigen wir deinen Namen, deine Anschrift, deine Telefonnummer, deine E-" +#~ "Mail-Adresse und deine Zahlungsdaten um deine Aufträge zu verarbeiten. " +#~ "
Bei der Zahlung mittels Kreditkarte erfassen und speichern wir keine " +#~ "Zahlungsverkehrsinformationen wie Kreditkartennummern, das Ablaufdatum " +#~ "oder die Prüfziffer. Diese gibst du ausschließlich direkt dem " +#~ "entsprechenden Zahlungsdienstleister bekannt. Bei der Bezahlung mit " +#~ "Kreditkarte erfolgt die Abwicklung der Bezahlung durch einen externen " +#~ "Dienstleister.
Für die Kreditkartenzahlung werden deine Angaben " +#~ "direkt vom Diensteanbieter Stripe Payments Europe Ltd. („Stripe“) " +#~ "verarbeitet.

II. Serverlogdateien

Bei " +#~ "jedem Aufruf einer unserer Internetseiten speichern wir automatisch " +#~ "bestimmte Daten. Dazu gehören u. a. deine IP-Adresse, Typ und Version des " +#~ "verwendeten Browsers, Uhrzeit, Datum und die Webseite von der du auf " +#~ "unsere Seite gelangst (sog. „Referer“). Deine IP-Adresse wird bei uns nur " +#~ "anonymisiert gespeichert, sodass ein Personenbezug nicht mehr herstellbar " +#~ "ist. Die Erfassung der Daten zur Bereitstellung unserer Internetseiten " +#~ "und die Speicherung der Daten in den Server Logfiles ist für den Betrieb " +#~ "der Internetseite zwingend erforderlich und dient damit der Wahrung eines " +#~ "berechtigten Interesses unseres Unternehmens. Die Rechtsgrundlage für " +#~ "diese Verarbeitung ist Art. 6. Abs. 1 lit. f DSGVO.


4. Speicherdauer

Sofern die verarbeiteten " +#~ "personenbezogenen Daten für die Durchführung eines ggf.
geschlossenen " +#~ "Vertrages nicht mehr erforderlich sind, werden sie umgehend gelöscht. " +#~ "Jedoch kann es auch nach Abschluss des Vertrags erforderlich sein, " +#~ "personenbezogene Daten von dir zu speichern, um unseren vertraglichen " +#~ "oder gesetzlichen Verpflichtungen nachzukommen.


5. " +#~ "Weitergabe von personenbezogenen Daten

Wir geben deine " +#~ "personenbezogenen Daten grundsätzlich nicht an Dritte weiter, es sei denn:" +#~ "

a) Du erteilst uns hierzu deine ausdrückliche Einwilligung nach " +#~ "Art. 6 Abs. 1 S. 1 lit. a DSGVO.

b) Die Weitergabe der Daten ist " +#~ "gesetzlich zulässig und nach Art. 6. Abs. 1 S. 1 lit b DSGVO zur " +#~ "Erfüllung unserer vertraglichen Pflichten mit Ihnen erforderlich.

c) Für die Weitergabe der Daten besteht nach Art. 6. Abs. 1 S. 1 lit. c " +#~ "DSGVO eine gesetzliche Verpflichtung.

d) Die Weitergabe der " +#~ "Daten ist nach Art. 6. Abs. 1 S. 1 lit. f DSGVO zur Wahrung unserer " +#~ "berechtigten Interessen, sowie zur Geltendmachung, Ausübung oder " +#~ "


6. Cookies, Google Analytics und Twitter

Wir " +#~ "setzen auf unseren Internetseiten sog. „Cookies“ ein. Cookies sind kleine " +#~ "Textdateien, die im Rahmen deines Besuchs einer unserer Internetseiten " +#~ "von uns an den Browser deines Endgeräts gesendet und dort gespeichert " +#~ "werden. Einige Funktionen unseres Angebots können ohne den Einsatz " +#~ "bestimmter Cookies grundsätzlich aus technischen Gründen nicht angeboten " +#~ "werden. Du kannst deinen Browser allerdings so konfigurieren, dass er nur " +#~ "noch bestimmte oder auch gar keine Cookies mehr akzeptiert. Es kann " +#~ "jedoch passieren, dass du dadurch möglicherweise nicht mehr alle " +#~ "Funktionen unserer Internetseiten nutzen kannst.
Andere Cookies " +#~ "ermöglichen es uns hingegen verschiedene Analysen deines Verhaltens oder " +#~ "etwa eine Verbindung zu deinen sozialen Netzwerken aufzubauen. Mithilfe " +#~ "dieser Cookies können wir beispielsweise unser Internetangebot für dich " +#~ "nutzerfreundlicher und effektiver gestalten. Daraus folgt, dass wir auf " +#~ "Grundlage unserer berechtigten Unternehmensinteressen (Optimierung und " +#~ "wirtschaftlicher Betrieb unseres Internetangebots) den Werbeanalysedienst " +#~ "„Google Analytics“ der Google Inc., 1600 Amphitheatre Parkway, " +#~ "Mountainview, CA 94043, Vereinigte Staaten von Amerika („Google“) " +#~ "einsetzen. Google verwendet Cookies. Die durch das Cookie erzeugten " +#~ "Informationen werden an einen Server von Google in den Vereinigten " +#~ "Staaten von Amerika übertragen und dort erhoben und gespeichert. Google " +#~ "nutzt dies Informationen in unserem Auftrag dafür, die Nutzung unseres " +#~ "Internetangebots auszuwerten und Berichte über die Aktivitäten auf " +#~ "unserem Onlineangebot uns gegenüber zu erbringen.
Dabei werden aus " +#~ "den verarbeiteten Daten anonymisierte bzw. pseudonyme Nutzungsprofile " +#~ "einiger Nutzer erstellt. Diese Nutzungsprofile sind nicht auf eine IP-" +#~ "Adresse oder einen spezifischen Nutzer zurückzuführen. Darüber hinaus " +#~ "setzen wir Google Analytics nur mit IP-Anonymisierung ein. Das heißt, " +#~ "dass die IP-Adresse von Google gekürzt wird. Nur in wenigen " +#~ "Ausnahmefällen wird die vollständige IP-Adresse an Google übertragen und " +#~ "dort gekürzt. Du kannst der Verarbeitung von deinen erfassten Daten durch " +#~ "die Installation dieses Browserplugins widersprechen:
http://tools.google.com/dlpage/" +#~ "gaoptout?hl=de

Weitere Informationen zur Nutzung der Daten " +#~ "durch Google und weiterführende Widerspruchsmöglichkeiten erhältst du in " +#~ "der Datenschutzerklärung von Google:

https://policies.google.com/technologies/" +#~ "ads

und auf den folgenden Webseiten:

https://www.privacyshield.gov/" +#~ "participant?id=a2zt000000001L5AAI&status=Active

https://adssettings." +#~ "google.com/authenticated

Die personenbezogenen Daten werden " +#~ "nach 14 Monaten gelöscht oder anonymisiert.
Rechtliche Grundlage " +#~ "hierfür ist Art. 6 Abs. 1 lit. f DSGVO.

Innerhalb unseres " +#~ "Onlineangebots können Funktionen und Inhalte des Dienstes Twitter " +#~ "eingebunden werden. Twitter ist ein Dienst der Twitter Inc., 1355 Market " +#~ "Street, Suite 900, San Francisco, CA 94103, Vereinigte Staaten von " +#~ "Amerika. Hierzu können beispielsweise Inhalte wie Bilder, Videos oder " +#~ "Texte und Schaltflächen gehören. Sofern du Mitglied der Plattform Twitter " +#~ "bist, kann Twitter den Aufruf der Funktionalitäten deinem dortigen Profil " +#~ "zuordnen.
Weitere Informationen zum Datenschutz bei Twitter, findest " +#~ "du in der Datenschutzerklärung von
Twitter unter https://twitter.com/de/privacy.



7. Rechte des Betroffenen

Aus der DSGVO " +#~ "ergeben sich für dich als Betroffener die folgenden Rechte:

a) " +#~ "Du kannst gem. Art. 15 DSGVO Auskunft über deine von uns verarbeiteten " +#~ "personenbezogenen Daten verlangen. Du kannst insbesondere Auskunft über " +#~ "den Zweck der Verarbeitung, die Kategorien der erhobenen " +#~ "personenbezogenen Daten, die Kategorien von Dritten, gegenüber denen " +#~ "deine Daten offengelegt werden und die voraussichtliche Speicherdauer " +#~ "verlangen.

b) Du hast gem. Art. 15 u. Art. 16 DSGVO ein Recht " +#~ "auf Berichtigung, Vervollständigung, Löschung und die Bestimmung von " +#~ "Einschränkungen hinsichtlich der Verarbeitung deiner personenbezogenen " +#~ "Daten.

c) Gemäß Art. 17 DSGVO kannst du von uns die Löschung " +#~ "deiner bei uns gespeicherten personenbezogenen Daten verlangen, soweit " +#~ "die Verarbeitung nicht zur Erfüllung unserer rechtlichen Verpflichtungen, " +#~ "aus Gründen des öffentlichen Interesses oder zur Geltendmachung, Ausübung " +#~ "oder Verteidigung von Rechtsansprüchen erforderlich ist.

d) " +#~ "Gemäß Art. 18 DSGVO kannst du von uns die Einschränkung der Verarbeitung " +#~ "deiner personenbezogenen Daten verlangen, soweit die Richtigkeit der " +#~ "Daten von dir bestritten wird, die Verarbeitung grundsätzlich " +#~ "unrechtmäßig ist oder die Löschung deiner
personenbezogenen Daten " +#~ "durch uns ablehnen, weil du diese zur Geltendmachung, Ausübung oder " +#~ "Verteidigung von Rechtsansprüchen benötigst.

e) Gemäß Art. 20 " +#~ "DSGVO kannst du von uns verlangen, dass deine personenbezogenen Daten, " +#~ "die du uns zur Verfügung gestellt hast, in einem strukturierten, " +#~ "maschinenlesbaren und gängigen Format zu erhalten oder du kannst die " +#~ "Übermittlung an eine andere Stelle verlangen.

f) Gemäß Art. 7 " +#~ "Abs. 3 DSGVO kannst du deine erteilte Einwilligung gegenüber uns " +#~ "jederzeit widerrufen. Dies hat zur Folge, dass wir die auf dieser " +#~ "Einwilligung beruhende Datenverarbeitung für die Zukunft nicht mehr " +#~ "fortführen dürfen.

g) Gemäß Art. 77 DSGVO steht dir das Recht " +#~ "zu, dich bei einer Aufsichtsbehörde zu beschweren.


8. Hyperlinks und Haftungsausschluss

Auf " +#~ "unseren Internetseiten befinden sich sog. „Hyperlinks“, also Verbindungen " +#~ "bzw.
Weiterleitungen zu den Internetseiten Dritter. Bei Aktivierung " +#~ "dieser Hyperlinks durch Anklicken, wirst du von unserer Internetseite " +#~ "direkt auf die Internetseite eines Dritten weitergeleitet. Wir können " +#~ "keine Verantwortung für den vertraulichen Umgang deiner Daten auf diesen " +#~ "Webseiten Dritter übernehmen, da wir keinen Einfluss darauf haben, dass " +#~ "diese Unternehmen die Datenschutzbestimmungen der DSGVO einhalten. Wir " +#~ "weisen dich außerdem darauf hin, dass es aufgrund der Struktur des " +#~ "Internets möglich ist, dass die Regelungen des Datenschutzes bzw. der " +#~ "DSGVO von anderen, dritten Personen oder Institutionen die nicht " +#~ "innerhalb unseres Verantwortungsbereichs liegen nicht beachtet werden, " +#~ "oder dass sich spontan, kurzfristig schwerwiegende Sicherheitslücken in " +#~ "verbreiteten Standards und technischen Protokollen auftun, die die " +#~ "Datenintegrität gefährden könnten.

\n" +#~ " " #~ msgid "Accept" #~ msgstr "Annehmen" diff --git a/dynamicweb/settings/base.py b/dynamicweb/settings/base.py index 03013ea5..62fe2897 100644 --- a/dynamicweb/settings/base.py +++ b/dynamicweb/settings/base.py @@ -631,8 +631,6 @@ GOOGLE_ANALYTICS_PROPERTY_IDS = { 'datacenterlight.ch': 'UA-62285904-8', 'devuanhosting.ch': 'UA-62285904-9', 'devuanhosting.com': 'UA-62285904-9', - 'ipv6onlyhosting.ch': 'UA-62285904-10', - 'ipv6onlyhosting.net': 'UA-62285904-10', 'ipv6onlyhosting.com': 'UA-62285904-10', 'comic.ungleich.ch': 'UA-62285904-13', '127.0.0.1:8000': 'localhost', diff --git a/dynamicweb/settings/prod.py b/dynamicweb/settings/prod.py index 445748ad..0590ca27 100644 --- a/dynamicweb/settings/prod.py +++ b/dynamicweb/settings/prod.py @@ -28,9 +28,7 @@ ALLOWED_HOSTS = [ ".devuanhosting.ch", ".devuanhosting.com", ".digitalezukunft.ch", - ".ipv6onlyhosting.ch", ".ipv6onlyhosting.com", - ".ipv6onlyhosting.net", ".digitalglarus.ch", ".hack4glarus.ch", ".xn--nglarus-n2a.ch" diff --git a/templates/gdpr/gdpr_banner.html b/templates/gdpr/gdpr_banner.html index 7e9f5c7f..f927f8ee 100644 --- a/templates/gdpr/gdpr_banner.html +++ b/templates/gdpr/gdpr_banner.html @@ -134,8 +134,6 @@ digitalglarus.ch
hack4lgarus.ch
ipv6onlyhosting.com
- ipv6onlyhosting.ch
- ipv6onlyhosting.net
django-hosting.ch
rails-hosting.ch
node-hosting.ch
From 338ff38bbbfd11b491fd1f6cef6ad8656e678c80 Mon Sep 17 00:00:00 2001 From: Tomislav R Date: Mon, 16 May 2022 11:37:30 +0200 Subject: [PATCH 02/60] Actual po --- digitalglarus/locale/de/LC_MESSAGES/django.po | 1164 ++++++++++------- 1 file changed, 656 insertions(+), 508 deletions(-) diff --git a/digitalglarus/locale/de/LC_MESSAGES/django.po b/digitalglarus/locale/de/LC_MESSAGES/django.po index d5a50d71..ef7a46b5 100644 --- a/digitalglarus/locale/de/LC_MESSAGES/django.po +++ b/digitalglarus/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-05-16 08:56+0000\n" +"POT-Creation-Date: 2019-01-31 23:53+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,6 +18,39 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +msgid "Posted on" +msgstr "Veröffentlicht am" + +msgid "Articles by" +msgstr "Artikel vom" + +msgid "Archive" +msgstr "Archiv" + +msgid "Tag" +msgstr "" + +msgid "Category" +msgstr "Kategorie" + +msgid "No article found." +msgstr "Keine Artikel gefunden" + +msgid "Back" +msgstr "Zurück" + +msgid "Newer Posts" +msgstr "Neuere Einträge" + +msgid "Older Posts" +msgstr "Ältere Einträge" + +msgid "read more" +msgstr "weiterlesen" + +msgid "by" +msgstr "von" + msgid "Digital Glarus Gallery" msgstr "" @@ -36,27 +69,9 @@ msgstr "Postleitzahl" msgid "Country" msgstr "Land" -msgid "VAT Number" -msgstr "" - msgid "You haven been logged out" msgstr "Sie wurden abgemeldet" -msgid "Posted on" -msgstr "Veröffentlicht am" - -msgid "read more" -msgstr "weiterlesen" - -msgid "by" -msgstr "von" - -msgid "No article found." -msgstr "Keine Artikel gefunden" - -msgid "Back" -msgstr "Zurück" - msgid "previous" msgstr "vorherige" @@ -149,506 +164,638 @@ msgstr "befurworter/?$" msgid "Message Successfully Sent" msgstr "" -#~ msgid "Articles by" -#~ msgstr "Artikel vom" +msgid "US English" +msgstr "" -#~ msgid "Archive" -#~ msgstr "Archiv" +msgid "German" +msgstr "" -#~ msgid "Category" -#~ msgstr "Kategorie" +msgid "Content" +msgstr "" -#~ msgid "Newer Posts" -#~ msgstr "Neuere Einträge" +msgid "default" +msgstr "" -#~ msgid "Older Posts" -#~ msgstr "Ältere Einträge" +msgid "2 Column" +msgstr "" + +msgid "3 Column" +msgstr "" + +msgid "DG.About" +msgstr "" #, fuzzy -#~| msgid "contact/?$" -#~ msgid "DG.Contact" -#~ msgstr "kontakt/?$" +#| msgid "contact/?$" +msgid "DG.Contact" +msgstr "kontakt/?$" -#~ msgid "Amount" -#~ msgstr "Betrag" +msgid "DG.Home" +msgstr "" -#~ msgid "" -#~ "This site uses cookies for analytics. By continuing to\n" -#~ " browse this site, you agree to use this." -#~ msgstr "" -#~ "Diese Website verwendet Cookies für Analysezwecke. Mit dem weiterem " -#~ "Besuch dieser Website erklärst Du Dich damit einverstanden, diese zu " -#~ "nutzen." +msgid "DG.CoWork" +msgstr "" -#~ msgid "Learn more" -#~ msgstr "Lerne mehr" +msgid "DG.OneColumn" +msgstr "" -#~ msgid "Privacy policy" -#~ msgstr "Datenschutz-Bestimmungen" +msgid "Blog" +msgstr "" -#~ msgid "" -#~ "\n" -#~ " 1. Responsibility and scope
\n" -#~ "
\n" -#~ " Responsible in regards to EU General Data Protection\n" -#~ " Regulation (\"GDPR\") and other applicable data " -#~ "protection\n" -#~ " laws:
\n" -#~ "
\n" -#~ " ungleich glarus ag
\n" -#~ " Bahnhofstrasse 1
\n" -#~ " 8783 Linthal (CH)
\n" -#~ " Tel.: +41 55 505 6266
\n" -#~ " E-Mail: info@ungleich.ch
\n" -#~ "
\n" -#~ " This privacy statement applies to the web content of\n" -#~ " ungleich glarus ag, available at the
\n" -#~ " following domains:
\n" -#~ "
\n" -#~ " ungleich.ch
\n" -#~ " datacenterlight.ch
\n" -#~ " devuanhosting.com
\n" -#~ " devuanhosting.ch
\n" -#~ " digitalglarus.ch
\n" -#~ " hack4lgarus.ch
\n" -#~ " ipv6onlyhosting.com
\n" -#~ " ipv6onlyhosting.ch
\n" -#~ " ipv6onlyhosting.net
\n" -#~ " django-hosting.ch
\n" -#~ " rails-hosting.ch
\n" -#~ " node-hosting.ch
\n" -#~ " blog.ungleich.ch
\n" -#~ "
\n" -#~ " The Data Privacy Officer:
\n" -#~ "
\n" -#~ " Sanghee Kim
\n" -#~ " ungleich glarus ag
\n" -#~ " Bahnhofstrasse 1
\n" -#~ " 8783 Linthal (CH)
\n" -#~ " E-Mail: sanghee.kim@ungleich.ch
\n" -#~ "
\n" -#~ "
\n" -#~ " 2. General
\n" -#~ "
\n" -#~ " User data is personal data which is necessary to " -#~ "establish\n" -#~ " or change the contractual relations\n" -#~ " between ungleich glarus ag (\"us\") and you. This " -#~ "includes\n" -#~ " among other things for example the\n" -#~ " name, the address, the date of birth, the e-mail " -#~ "address or\n" -#~ " the IP address. We save and use\n" -#~ " your personal data only for the processing of your " -#~ "orders\n" -#~ " or for getting in contact with you.
\n" -#~ "
\n" -#~ "
\n" -#~ " 3. Processing of personal data
\n" -#~ "
\n" -#~ " When you call one of our websites we collect your IP\n" -#~ " address. When you register an account with us your " -#~ "contact\n" -#~ " data will be stored. When you order products on our\n" -#~ " platform we also collect among others your address " -#~ "and your\n" -#~ " payment details.
\n" -#~ "
\n" -#~ " I. Registration data
\n" -#~ "
\n" -#~ " In the process of registration we need to collect " -#~ "some of\n" -#~ " your personal data. For example we collect your name, " -#~ "your\n" -#~ " address, your telephone number, your e-mail address " -#~ "and\n" -#~ " your payment details to process orders. We do not " -#~ "collect\n" -#~ " your payment details such as credit card number, " -#~ "expiration\n" -#~ " date or the cvv code when you pay with credit card. " -#~ "You\n" -#~ " expose those data directly to the respective payment\n" -#~ " processor. Payments with credit card are processed " -#~ "by\n" -#~ " Stripe Payments Europe Ltd. (\"Stripe\").
\n" -#~ "
\n" -#~ "
\n" -#~ " II. Server log files
\n" -#~ "
\n" -#~ " When you call one of our websites we automatically " -#~ "save\n" -#~ " traffic data. Normally the IP address, the type and " -#~ "version\n" -#~ " of your browser, the time and the website that lead " -#~ "to our\n" -#~ " website (\"Referer\") will be saved. Your IP address " -#~ "is\n" -#~ " collected anonymously so that we cannot match it with " -#~ "your\n" -#~ " person. The collection of those data is necessary to\n" -#~ " provide our websites and services, according to Art. " -#~ "6 par.\n" -#~ " 1 lit. f GDPR.
\n" -#~ "
\n" -#~ "
\n" -#~ " 4. Storage durations
\n" -#~ "
\n" -#~ " Your data will be deleted immediately, as soon as it " -#~ "isn't\n" -#~ " relevant anymore for any contract between you and us. " -#~ "In\n" -#~ " some cases it could be necessary to store your data\n" -#~ " further, to comply with our contractual or other " -#~ "legal\n" -#~ " obligatons.
\n" -#~ "
\n" -#~ "
\n" -#~ " 5. Disclosure of your personal data
\n" -#~ "
\n" -#~ " We don't disclose your personal data to third " -#~ "parties,\n" -#~ " except:
\n" -#~ "
\n" -#~ " a) You grant us your explicit permission according to " -#~ "Art.\n" -#~ " 6 par. 1 S. 1 lit. a GDPR.
\n" -#~ "
\n" -#~ " b) The disclosure of your data is legal and it is " -#~ "necessary\n" -#~ " to comply with our contractual or other legal " -#~ "obligations,\n" -#~ " according to Art. 6 par. 1 S. 1 lit b GDPR.
\n" -#~ "
\n" -#~ " c) There is a law or legal obligation to disclose " -#~ "your data\n" -#~ " or the disclosure is necessary for the performance of " -#~ "a\n" -#~ " task carried out in the public interest or in the " -#~ "exercise\n" -#~ " of an official authority according to Art. 6 par. 1 " -#~ "S. 1\n" -#~ " lit. c GDPR.
\n" -#~ "
\n" -#~ " d) The disclosure of your data is necessary for the\n" -#~ " purposes of the legitimate interests pursued by us or " -#~ "by a\n" -#~ " third party, except where such interests are " -#~ "overridden by\n" -#~ " the interests or your fundamental right according to " -#~ "Art.\n" -#~ " 6. par. 1 S. 1 lit. f GDPR.
\n" -#~ "
\n" -#~ "
\n" -#~ " 6. Cookies, Google Analytics, Twitter
\n" -#~ "
\n" -#~ " We use Cookies. When you visit one of our websites,\n" -#~ " information is stored on your terminal device in the " -#~ "form\n" -#~ " of a \"cookie\". Cookies are small text files that " -#~ "are stored\n" -#~ " on your terminal device by your browser. You can opt-" -#~ "out of\n" -#~ " the storage of cookies in the settings of your\n" -#~ " browser-software, but however, in this case you might " -#~ "not\n" -#~ " be able to fully use all functions and services on " -#~ "our\n" -#~ " website.
\n" -#~ "
\n" -#~ " We use Google Analytics, a service provided by Google " -#~ "Inc.,\n" -#~ " 1600 Amphitheatre Parkway, Mountainview, CA 94043, " -#~ "USA\n" -#~ " (\"Google\"). Google uses Cookies. Google will use " -#~ "these\n" -#~ " cookies on our behalf to analyse how you use our " -#~ "websites\n" -#~ " and to generate reports about the activities on our\n" -#~ " websites. The information collected by those cookies " -#~ "will\n" -#~ " be transmitted to a Google server in the United " -#~ "States of\n" -#~ " America. We have Google's IP anonymization activated, " -#~ "so\n" -#~ " your IP address will be shortened before transmitting " -#~ "to\n" -#~ " Google. Only in exceptional cases the full IP address " -#~ "will\n" -#~ " be transmitted and then shortened afterwards.
\n" -#~ "
\n" -#~ " You may opt out from thecollection of these cookies " -#~ "by\n" -#~ " downloading and installing a browser plugin available " -#~ "at\n" -#~ " the following link:
\n" -#~ "
\n" -#~ " http://tools.google.com/dlpage/gaoptout
\n" -#~ "
\n" -#~ " You may find further information about the processing " -#~ "of\n" -#~ " your personal data at the following links:
\n" -#~ "
\n" -#~ " https://policies.google.com/technologies/ads
\n" -#~ "
\n" -#~ " https://www.privacyshield.gov/" -#~ "participant?id=a2zt000000001L5AAI&status=Active
\n" -#~ "
\n" -#~ " https://adssettings.google.com/authenticated
\n" -#~ "
\n" -#~ " The collected personal data will be deleted or " -#~ "anonymized\n" -#~ " after 14 months according to Art. 6 par. 1 lit. f\n" -#~ " GDPR.
\n" -#~ "
\n" -#~ " Our websites use several functions from the social " -#~ "network\n" -#~ " Twitter, a service provided by Twitter Inc., 1355 " -#~ "Market\n" -#~ " Street, Suite 900, San Francisco, CA 94103, USA. We " -#~ "may\n" -#~ " embed content of Twitter in our websites, such as " -#~ "photos,\n" -#~ " videos, texts or buttons. If you are registered with\n" -#~ " Twitter, they may combine your use of these " -#~ "functionalities\n" -#~ " on our websites with your Twitter account. You may " -#~ "find\n" -#~ " further information at https://twitter.com/de/privacy." -#~ "
\n" -#~ "
\n" -#~ "
\n" -#~ " 7. Your rights concerning your personal\n" -#~ " data
\n" -#~ "
\n" -#~ " Under applicable GDPR you may have the right to:
\n" -#~ "
\n" -#~ " a) Obtain confirmation as to whether or not personal " -#~ "data\n" -#~ " concerning you are being processed, and where that is " -#~ "the\n" -#~ " case, access to the personal data, according to Art. " -#~ "15\n" -#~ " GDPR.
\n" -#~ "
\n" -#~ " b) Obtain the rectification of false or inaccurate " -#~ "data\n" -#~ " concerning you, according to Art. 15, Art. 16 GDPR." -#~ "
\n" -#~ "
\n" -#~ " c) Obtain the deletion of your personal data, " -#~ "according to\n" -#~ " Art. 17 GDPR.
\n" -#~ "
\n" -#~ " d) Obtain the restriction of processing your personal " -#~ "data,\n" -#~ " according to Art. 18 GDPR.
\n" -#~ "
\n" -#~ " e) Obtain a digital copy of your personal data " -#~ "processed by\n" -#~ " us, according to Art. 20 GDPR.
\n" -#~ "
\n" -#~ " f) Revoke a granted permission regarding your " -#~ "personal data\n" -#~ " at any time, according to Art. 7 par. 3 GDPR.
\n" -#~ "
\n" -#~ " g) Complain at a data protection authority, according " -#~ "to\n" -#~ " Art. 77 GDPR.
\n" -#~ "
\n" -#~ "
\n" -#~ "
\n" -#~ " 8. Hyperlinks / Disclaimer
\n" -#~ "
\n" -#~ " This privacy policy applies only to our websites and " -#~ "not to\n" -#~ " other websites or applications operated by third " -#~ "parties.\n" -#~ " We may provide links to other websites but we are " -#~ "not\n" -#~ " responsible for the privacy practices of such other\n" -#~ " websites.
\n" -#~ "
\n" -#~ "
\n" -#~ " " -#~ msgstr "" -#~ "\n" -#~ "1. Verantwortung und Geltungsbereich

Verantwortlich im Sinne der EU-Datenschutzgrundverordnung („DSGVO“) und " -#~ "sonstiger datenschutzrechtlicher Bestimmungen ist:

ungleich " -#~ "glarus ag
Bahnhofstrasse 1
8783 Linthal (CH)
Tel.: +41 55 505 " -#~ "6266
E-Mail: info@ungleich.ch

Diese Datenschutzerklärung " -#~ "gilt für das Internetangebot der ungleich glarus ag, welches unter den " -#~ "nachfolgenden Domains erreichbar ist:

ungleich.ch
datacenterlight.ch
devuanhosting.com
devuanhosting.ch
digitalglarus.ch
hack4lgarus.ch
ipv6onlyhosting.com
ipv6onlyhosting.ch
ipv6onlyhosting.net
django-hosting.ch
rails-hosting.ch
node-hosting.ch
blog.ungleich.ch

Der " -#~ "Datenschutzbeauftragte des Verantwortlichen ist:

Sanghee Kim
ungleich glarus ag
Bahnhofstrasse 1
8783 Linthal (CH)
E-" -#~ "Mail: sanghee.kim@ungleich.ch


2. Grundsätzliches

Bei " -#~ "personenbezogenen Daten handelt es sich um alle Informationen, die sich " -#~ "auf eine identifizierte oder identifizierbare natürliche Person beziehen. " -#~ "Hierzu gehört zum Beispiel dein Name, deine Anschrift, dein Geburtsdatum, " -#~ "deine E-Mail-Adresse oder deine IP-Adresse. Wir speichern und verwenden " -#~ "deine personenbezogenen Daten ausschließlich für die Bearbeitung deiner " -#~ "Aufträge und für die Kontaktaufnahme mit dir.


3. " -#~ "Verarbeitung deiner personenbezogenen Daten

Bei jedem " -#~ "Aufruf einer unserer Internetseiten wird u. a. deine IP-Adresse " -#~ "gespeichert. Wenn du dich bei uns registrierst, werden deine Kontaktdaten " -#~ "gespeichert. Wenn du Aufträge an uns richtest oder Produkte bei uns " -#~ "bestellst, werden darüber hinaus auch deine Anschrift und deine
Zahlungsdaten gespeichert.

I. Registrierungsdaten

Im Rahmen der Registrierung müssen wir einige " -#~ "personenbezogene Daten von dir erheben und verarbeiten. Beispielsweise " -#~ "benötigen wir deinen Namen, deine Anschrift, deine Telefonnummer, deine E-" -#~ "Mail-Adresse und deine Zahlungsdaten um deine Aufträge zu verarbeiten. " -#~ "
Bei der Zahlung mittels Kreditkarte erfassen und speichern wir keine " -#~ "Zahlungsverkehrsinformationen wie Kreditkartennummern, das Ablaufdatum " -#~ "oder die Prüfziffer. Diese gibst du ausschließlich direkt dem " -#~ "entsprechenden Zahlungsdienstleister bekannt. Bei der Bezahlung mit " -#~ "Kreditkarte erfolgt die Abwicklung der Bezahlung durch einen externen " -#~ "Dienstleister.
Für die Kreditkartenzahlung werden deine Angaben " -#~ "direkt vom Diensteanbieter Stripe Payments Europe Ltd. („Stripe“) " -#~ "verarbeitet.

II. Serverlogdateien

Bei " -#~ "jedem Aufruf einer unserer Internetseiten speichern wir automatisch " -#~ "bestimmte Daten. Dazu gehören u. a. deine IP-Adresse, Typ und Version des " -#~ "verwendeten Browsers, Uhrzeit, Datum und die Webseite von der du auf " -#~ "unsere Seite gelangst (sog. „Referer“). Deine IP-Adresse wird bei uns nur " -#~ "anonymisiert gespeichert, sodass ein Personenbezug nicht mehr herstellbar " -#~ "ist. Die Erfassung der Daten zur Bereitstellung unserer Internetseiten " -#~ "und die Speicherung der Daten in den Server Logfiles ist für den Betrieb " -#~ "der Internetseite zwingend erforderlich und dient damit der Wahrung eines " -#~ "berechtigten Interesses unseres Unternehmens. Die Rechtsgrundlage für " -#~ "diese Verarbeitung ist Art. 6. Abs. 1 lit. f DSGVO.


4. Speicherdauer

Sofern die verarbeiteten " -#~ "personenbezogenen Daten für die Durchführung eines ggf.
geschlossenen " -#~ "Vertrages nicht mehr erforderlich sind, werden sie umgehend gelöscht. " -#~ "Jedoch kann es auch nach Abschluss des Vertrags erforderlich sein, " -#~ "personenbezogene Daten von dir zu speichern, um unseren vertraglichen " -#~ "oder gesetzlichen Verpflichtungen nachzukommen.


5. " -#~ "Weitergabe von personenbezogenen Daten

Wir geben deine " -#~ "personenbezogenen Daten grundsätzlich nicht an Dritte weiter, es sei denn:" -#~ "

a) Du erteilst uns hierzu deine ausdrückliche Einwilligung nach " -#~ "Art. 6 Abs. 1 S. 1 lit. a DSGVO.

b) Die Weitergabe der Daten ist " -#~ "gesetzlich zulässig und nach Art. 6. Abs. 1 S. 1 lit b DSGVO zur " -#~ "Erfüllung unserer vertraglichen Pflichten mit Ihnen erforderlich.

c) Für die Weitergabe der Daten besteht nach Art. 6. Abs. 1 S. 1 lit. c " -#~ "DSGVO eine gesetzliche Verpflichtung.

d) Die Weitergabe der " -#~ "Daten ist nach Art. 6. Abs. 1 S. 1 lit. f DSGVO zur Wahrung unserer " -#~ "berechtigten Interessen, sowie zur Geltendmachung, Ausübung oder " -#~ "


6. Cookies, Google Analytics und Twitter

Wir " -#~ "setzen auf unseren Internetseiten sog. „Cookies“ ein. Cookies sind kleine " -#~ "Textdateien, die im Rahmen deines Besuchs einer unserer Internetseiten " -#~ "von uns an den Browser deines Endgeräts gesendet und dort gespeichert " -#~ "werden. Einige Funktionen unseres Angebots können ohne den Einsatz " -#~ "bestimmter Cookies grundsätzlich aus technischen Gründen nicht angeboten " -#~ "werden. Du kannst deinen Browser allerdings so konfigurieren, dass er nur " -#~ "noch bestimmte oder auch gar keine Cookies mehr akzeptiert. Es kann " -#~ "jedoch passieren, dass du dadurch möglicherweise nicht mehr alle " -#~ "Funktionen unserer Internetseiten nutzen kannst.
Andere Cookies " -#~ "ermöglichen es uns hingegen verschiedene Analysen deines Verhaltens oder " -#~ "etwa eine Verbindung zu deinen sozialen Netzwerken aufzubauen. Mithilfe " -#~ "dieser Cookies können wir beispielsweise unser Internetangebot für dich " -#~ "nutzerfreundlicher und effektiver gestalten. Daraus folgt, dass wir auf " -#~ "Grundlage unserer berechtigten Unternehmensinteressen (Optimierung und " -#~ "wirtschaftlicher Betrieb unseres Internetangebots) den Werbeanalysedienst " -#~ "„Google Analytics“ der Google Inc., 1600 Amphitheatre Parkway, " -#~ "Mountainview, CA 94043, Vereinigte Staaten von Amerika („Google“) " -#~ "einsetzen. Google verwendet Cookies. Die durch das Cookie erzeugten " -#~ "Informationen werden an einen Server von Google in den Vereinigten " -#~ "Staaten von Amerika übertragen und dort erhoben und gespeichert. Google " -#~ "nutzt dies Informationen in unserem Auftrag dafür, die Nutzung unseres " -#~ "Internetangebots auszuwerten und Berichte über die Aktivitäten auf " -#~ "unserem Onlineangebot uns gegenüber zu erbringen.
Dabei werden aus " -#~ "den verarbeiteten Daten anonymisierte bzw. pseudonyme Nutzungsprofile " -#~ "einiger Nutzer erstellt. Diese Nutzungsprofile sind nicht auf eine IP-" -#~ "Adresse oder einen spezifischen Nutzer zurückzuführen. Darüber hinaus " -#~ "setzen wir Google Analytics nur mit IP-Anonymisierung ein. Das heißt, " -#~ "dass die IP-Adresse von Google gekürzt wird. Nur in wenigen " -#~ "Ausnahmefällen wird die vollständige IP-Adresse an Google übertragen und " -#~ "dort gekürzt. Du kannst der Verarbeitung von deinen erfassten Daten durch " -#~ "die Installation dieses Browserplugins widersprechen:
http://tools.google.com/dlpage/" -#~ "gaoptout?hl=de

Weitere Informationen zur Nutzung der Daten " -#~ "durch Google und weiterführende Widerspruchsmöglichkeiten erhältst du in " -#~ "der Datenschutzerklärung von Google:

https://policies.google.com/technologies/" -#~ "ads

und auf den folgenden Webseiten:

https://www.privacyshield.gov/" -#~ "participant?id=a2zt000000001L5AAI&status=Active

https://adssettings." -#~ "google.com/authenticated

Die personenbezogenen Daten werden " -#~ "nach 14 Monaten gelöscht oder anonymisiert.
Rechtliche Grundlage " -#~ "hierfür ist Art. 6 Abs. 1 lit. f DSGVO.

Innerhalb unseres " -#~ "Onlineangebots können Funktionen und Inhalte des Dienstes Twitter " -#~ "eingebunden werden. Twitter ist ein Dienst der Twitter Inc., 1355 Market " -#~ "Street, Suite 900, San Francisco, CA 94103, Vereinigte Staaten von " -#~ "Amerika. Hierzu können beispielsweise Inhalte wie Bilder, Videos oder " -#~ "Texte und Schaltflächen gehören. Sofern du Mitglied der Plattform Twitter " -#~ "bist, kann Twitter den Aufruf der Funktionalitäten deinem dortigen Profil " -#~ "zuordnen.
Weitere Informationen zum Datenschutz bei Twitter, findest " -#~ "du in der Datenschutzerklärung von
Twitter unter https://twitter.com/de/privacy.



7. Rechte des Betroffenen

Aus der DSGVO " -#~ "ergeben sich für dich als Betroffener die folgenden Rechte:

a) " -#~ "Du kannst gem. Art. 15 DSGVO Auskunft über deine von uns verarbeiteten " -#~ "personenbezogenen Daten verlangen. Du kannst insbesondere Auskunft über " -#~ "den Zweck der Verarbeitung, die Kategorien der erhobenen " -#~ "personenbezogenen Daten, die Kategorien von Dritten, gegenüber denen " -#~ "deine Daten offengelegt werden und die voraussichtliche Speicherdauer " -#~ "verlangen.

b) Du hast gem. Art. 15 u. Art. 16 DSGVO ein Recht " -#~ "auf Berichtigung, Vervollständigung, Löschung und die Bestimmung von " -#~ "Einschränkungen hinsichtlich der Verarbeitung deiner personenbezogenen " -#~ "Daten.

c) Gemäß Art. 17 DSGVO kannst du von uns die Löschung " -#~ "deiner bei uns gespeicherten personenbezogenen Daten verlangen, soweit " -#~ "die Verarbeitung nicht zur Erfüllung unserer rechtlichen Verpflichtungen, " -#~ "aus Gründen des öffentlichen Interesses oder zur Geltendmachung, Ausübung " -#~ "oder Verteidigung von Rechtsansprüchen erforderlich ist.

d) " -#~ "Gemäß Art. 18 DSGVO kannst du von uns die Einschränkung der Verarbeitung " -#~ "deiner personenbezogenen Daten verlangen, soweit die Richtigkeit der " -#~ "Daten von dir bestritten wird, die Verarbeitung grundsätzlich " -#~ "unrechtmäßig ist oder die Löschung deiner
personenbezogenen Daten " -#~ "durch uns ablehnen, weil du diese zur Geltendmachung, Ausübung oder " -#~ "Verteidigung von Rechtsansprüchen benötigst.

e) Gemäß Art. 20 " -#~ "DSGVO kannst du von uns verlangen, dass deine personenbezogenen Daten, " -#~ "die du uns zur Verfügung gestellt hast, in einem strukturierten, " -#~ "maschinenlesbaren und gängigen Format zu erhalten oder du kannst die " -#~ "Übermittlung an eine andere Stelle verlangen.

f) Gemäß Art. 7 " -#~ "Abs. 3 DSGVO kannst du deine erteilte Einwilligung gegenüber uns " -#~ "jederzeit widerrufen. Dies hat zur Folge, dass wir die auf dieser " -#~ "Einwilligung beruhende Datenverarbeitung für die Zukunft nicht mehr " -#~ "fortführen dürfen.

g) Gemäß Art. 77 DSGVO steht dir das Recht " -#~ "zu, dich bei einer Aufsichtsbehörde zu beschweren.


8. Hyperlinks und Haftungsausschluss

Auf " -#~ "unseren Internetseiten befinden sich sog. „Hyperlinks“, also Verbindungen " -#~ "bzw.
Weiterleitungen zu den Internetseiten Dritter. Bei Aktivierung " -#~ "dieser Hyperlinks durch Anklicken, wirst du von unserer Internetseite " -#~ "direkt auf die Internetseite eines Dritten weitergeleitet. Wir können " -#~ "keine Verantwortung für den vertraulichen Umgang deiner Daten auf diesen " -#~ "Webseiten Dritter übernehmen, da wir keinen Einfluss darauf haben, dass " -#~ "diese Unternehmen die Datenschutzbestimmungen der DSGVO einhalten. Wir " -#~ "weisen dich außerdem darauf hin, dass es aufgrund der Struktur des " -#~ "Internets möglich ist, dass die Regelungen des Datenschutzes bzw. der " -#~ "DSGVO von anderen, dritten Personen oder Institutionen die nicht " -#~ "innerhalb unseres Verantwortungsbereichs liegen nicht beachtet werden, " -#~ "oder dass sich spontan, kurzfristig schwerwiegende Sicherheitslücken in " -#~ "verbreiteten Standards und technischen Protokollen auftun, die die " -#~ "Datenintegrität gefährden könnten.

\n" -#~ " " +msgid "Data Center Light" +msgstr "" + +msgid "Glasfaser" +msgstr "" + +msgid "ungleich" +msgstr "" + +msgid "English" +msgstr "" + +msgid "Deutsch" +msgstr "" + +msgid "Datacenterlight Navbar" +msgstr "" + +msgid "Datacenterlight Footer" +msgstr "" + +msgid "Datacenterlight Calculator" +msgstr "" + +msgid "Amount" +msgstr "Betrag" + +msgid "My Donations" +msgstr "" + +msgid "Set your new password" +msgstr "" + +msgid "Reset" +msgstr "" + +msgid "Already have an account ?" +msgstr "" + +msgid "Log in" +msgstr "" + +msgid "Invoice" +msgstr "" + +msgid "Donation #" +msgstr "" + +msgid "Billing Address:" +msgstr "" + +msgid "Date:" +msgstr "" + +msgid "Payment Method:" +msgstr "" + +msgid "Donation summary" +msgstr "" + +msgid "Donation" +msgstr "" + +msgid "Total" +msgstr "" + +msgid "Finish Configuration" +msgstr "" + +msgid "" +"Thanks for you donation, you can cancel your monthly donation at any time " +"going to profile > subscription " +msgstr "" + +msgid "View Donations" +msgstr "" + +msgid "Cancel Donation" +msgstr "" + +msgid "Donate" +msgstr "" + +msgid "Donations Made" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "View Detail" +msgstr "" + +msgid "Reanude Donation" +msgstr "" + +#, python-format +msgid "" +"You're receiving this email because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" + +msgid "Please go to the following page and choose a new password:" +msgstr "" + +msgid "Thanks for using our site!" +msgstr "" + +#, python-format +msgid "The %(site_name)s team" +msgstr "" + +msgid "Log in " +msgstr "" + +msgid "Login" +msgstr "" + +msgid "Don't have an account yet ? " +msgstr "" + +msgid "Sign up" +msgstr "" + +msgid "Forgot your password ? " +msgstr "" + +msgid "Reset your password" +msgstr "" + +msgid "DG.Detail" +msgstr "" + +msgid "" +"This site uses cookies for analytics. By continuing to\n" +" browse this site, you agree to use this." +msgstr "" +"Diese Website verwendet Cookies für Analysezwecke. Mit dem weiterem Besuch " +"dieser Website erklärst Du Dich damit einverstanden, diese zu nutzen." + +msgid "Learn more" +msgstr "Lerne mehr" + +msgid "OK" +msgstr "" + +msgid "Privacy policy" +msgstr "Datenschutz-Bestimmungen" + +msgid "" +"\n" +" 1. Responsibility and scope
\n" +"
\n" +" Responsible in regards to EU General Data Protection\n" +" Regulation (\"GDPR\") and other applicable data " +"protection\n" +" laws:
\n" +"
\n" +" ungleich glarus ag
\n" +" Bahnhofstrasse 1
\n" +" 8783 Linthal (CH)
\n" +" Tel.: +41 55 505 6266
\n" +" E-Mail: info@ungleich.ch
\n" +"
\n" +" This privacy statement applies to the web content of\n" +" ungleich glarus ag, available at the
\n" +" following domains:
\n" +"
\n" +" ungleich.ch
\n" +" datacenterlight.ch
\n" +" devuanhosting.com
\n" +" devuanhosting.ch
\n" +" digitalglarus.ch
\n" +" hack4lgarus.ch
\n" +" ipv6onlyhosting.com
\n" +" django-hosting.ch
\n" +" rails-hosting.ch
\n" +" node-hosting.ch
\n" +" blog.ungleich.ch
\n" +"
\n" +" The Data Privacy Officer:
\n" +"
\n" +" Sanghee Kim
\n" +" ungleich glarus ag
\n" +" Bahnhofstrasse 1
\n" +" 8783 Linthal (CH)
\n" +" E-Mail: sanghee.kim@ungleich.ch
\n" +"
\n" +"
\n" +" 2. General
\n" +"
\n" +" User data is personal data which is necessary to " +"establish\n" +" or change the contractual relations\n" +" between ungleich glarus ag (\"us\") and you. This " +"includes\n" +" among other things for example the\n" +" name, the address, the date of birth, the e-mail address " +"or\n" +" the IP address. We save and use\n" +" your personal data only for the processing of your " +"orders\n" +" or for getting in contact with you.
\n" +"
\n" +"
\n" +" 3. Processing of personal data
\n" +"
\n" +" When you call one of our websites we collect your IP\n" +" address. When you register an account with us your " +"contact\n" +" data will be stored. When you order products on our\n" +" platform we also collect among others your address and " +"your\n" +" payment details.
\n" +"
\n" +" I. Registration data
\n" +"
\n" +" In the process of registration we need to collect some " +"of\n" +" your personal data. For example we collect your name, " +"your\n" +" address, your telephone number, your e-mail address and\n" +" your payment details to process orders. We do not " +"collect\n" +" your payment details such as credit card number, " +"expiration\n" +" date or the cvv code when you pay with credit card. You\n" +" expose those data directly to the respective payment\n" +" processor. Payments with credit card are processed by\n" +" Stripe Payments Europe Ltd. (\"Stripe\").
\n" +"
\n" +"
\n" +" II. Server log files
\n" +"
\n" +" When you call one of our websites we automatically save\n" +" traffic data. Normally the IP address, the type and " +"version\n" +" of your browser, the time and the website that lead to " +"our\n" +" website (\"Referer\") will be saved. Your IP address is\n" +" collected anonymously so that we cannot match it with " +"your\n" +" person. The collection of those data is necessary to\n" +" provide our websites and services, according to Art. 6 " +"par.\n" +" 1 lit. f GDPR.
\n" +"
\n" +"
\n" +" 4. Storage durations
\n" +"
\n" +" Your data will be deleted immediately, as soon as it " +"isn't\n" +" relevant anymore for any contract between you and us. " +"In\n" +" some cases it could be necessary to store your data\n" +" further, to comply with our contractual or other legal\n" +" obligatons.
\n" +"
\n" +"
\n" +" 5. Disclosure of your personal data
\n" +"
\n" +" We don't disclose your personal data to third parties,\n" +" except:
\n" +"
\n" +" a) You grant us your explicit permission according to " +"Art.\n" +" 6 par. 1 S. 1 lit. a GDPR.
\n" +"
\n" +" b) The disclosure of your data is legal and it is " +"necessary\n" +" to comply with our contractual or other legal " +"obligations,\n" +" according to Art. 6 par. 1 S. 1 lit b GDPR.
\n" +"
\n" +" c) There is a law or legal obligation to disclose your " +"data\n" +" or the disclosure is necessary for the performance of a\n" +" task carried out in the public interest or in the " +"exercise\n" +" of an official authority according to Art. 6 par. 1 S. " +"1\n" +" lit. c GDPR.
\n" +"
\n" +" d) The disclosure of your data is necessary for the\n" +" purposes of the legitimate interests pursued by us or by " +"a\n" +" third party, except where such interests are overridden " +"by\n" +" the interests or your fundamental right according to " +"Art.\n" +" 6. par. 1 S. 1 lit. f GDPR.
\n" +"
\n" +"
\n" +" 6. Cookies, Google Analytics, Twitter
\n" +"
\n" +" We use Cookies. When you visit one of our websites,\n" +" information is stored on your terminal device in the " +"form\n" +" of a \"cookie\". Cookies are small text files that are " +"stored\n" +" on your terminal device by your browser. You can opt-out " +"of\n" +" the storage of cookies in the settings of your\n" +" browser-software, but however, in this case you might " +"not\n" +" be able to fully use all functions and services on our\n" +" website.
\n" +"
\n" +" We use Google Analytics, a service provided by Google " +"Inc.,\n" +" 1600 Amphitheatre Parkway, Mountainview, CA 94043, USA\n" +" (\"Google\"). Google uses Cookies. Google will use " +"these\n" +" cookies on our behalf to analyse how you use our " +"websites\n" +" and to generate reports about the activities on our\n" +" websites. The information collected by those cookies " +"will\n" +" be transmitted to a Google server in the United States " +"of\n" +" America. We have Google's IP anonymization activated, " +"so\n" +" your IP address will be shortened before transmitting " +"to\n" +" Google. Only in exceptional cases the full IP address " +"will\n" +" be transmitted and then shortened afterwards.
\n" +"
\n" +" You may opt out from thecollection of these cookies by\n" +" downloading and installing a browser plugin available " +"at\n" +" the following link:
\n" +"
\n" +" http://tools.google.com/dlpage/gaoptout
\n" +"
\n" +" You may find further information about the processing " +"of\n" +" your personal data at the following links:
\n" +"
\n" +" https://policies.google.com/technologies/ads
\n" +"
\n" +" https://www.privacyshield.gov/" +"participant?id=a2zt000000001L5AAI&status=Active
\n" +"
\n" +" https://adssettings.google.com/authenticated
\n" +"
\n" +" The collected personal data will be deleted or " +"anonymized\n" +" after 14 months according to Art. 6 par. 1 lit. f\n" +" GDPR.
\n" +"
\n" +" Our websites use several functions from the social " +"network\n" +" Twitter, a service provided by Twitter Inc., 1355 " +"Market\n" +" Street, Suite 900, San Francisco, CA 94103, USA. We may\n" +" embed content of Twitter in our websites, such as " +"photos,\n" +" videos, texts or buttons. If you are registered with\n" +" Twitter, they may combine your use of these " +"functionalities\n" +" on our websites with your Twitter account. You may find\n" +" further information at https://twitter.com/de/privacy." +"
\n" +"
\n" +"
\n" +" 7. Your rights concerning your personal\n" +" data
\n" +"
\n" +" Under applicable GDPR you may have the right to:
\n" +"
\n" +" a) Obtain confirmation as to whether or not personal " +"data\n" +" concerning you are being processed, and where that is " +"the\n" +" case, access to the personal data, according to Art. 15\n" +" GDPR.
\n" +"
\n" +" b) Obtain the rectification of false or inaccurate data\n" +" concerning you, according to Art. 15, Art. 16 GDPR.
\n" +"
\n" +" c) Obtain the deletion of your personal data, according " +"to\n" +" Art. 17 GDPR.
\n" +"
\n" +" d) Obtain the restriction of processing your personal " +"data,\n" +" according to Art. 18 GDPR.
\n" +"
\n" +" e) Obtain a digital copy of your personal data processed " +"by\n" +" us, according to Art. 20 GDPR.
\n" +"
\n" +" f) Revoke a granted permission regarding your personal " +"data\n" +" at any time, according to Art. 7 par. 3 GDPR.
\n" +"
\n" +" g) Complain at a data protection authority, according " +"to\n" +" Art. 77 GDPR.
\n" +"
\n" +"
\n" +"
\n" +" 8. Hyperlinks / Disclaimer
\n" +"
\n" +" This privacy policy applies only to our websites and not " +"to\n" +" other websites or applications operated by third " +"parties.\n" +" We may provide links to other websites but we are not\n" +" responsible for the privacy practices of such other\n" +" websites.
\n" +"
\n" +"
\n" +" " +msgstr "" +"\n" +"1. Verantwortung und Geltungsbereich

Verantwortlich im Sinne der EU-Datenschutzgrundverordnung („DSGVO“) und " +"sonstiger datenschutzrechtlicher Bestimmungen ist:

ungleich glarus " +"ag
Bahnhofstrasse 1
8783 Linthal (CH)
Tel.: +41 55 505 6266
E-Mail: info@ungleich.ch

Diese Datenschutzerklärung gilt für das " +"Internetangebot der ungleich glarus ag, welches unter den nachfolgenden " +"Domains erreichbar ist:

ungleich.ch
datacenterlight.ch
devuanhosting.com
devuanhosting.ch
digitalglarus.ch
hack4lgarus." +"ch
ipv6onlyhosting.com
django-hosting.ch
rails-hosting.ch" +"
node-hosting.ch
blog." +"ungleich.ch

Der Datenschutzbeauftragte des Verantwortlichen ist:

Sanghee Kim
ungleich glarus ag
Bahnhofstrasse 1
8783 " +"Linthal (CH)
E-Mail: sanghee." +"kim@ungleich.ch


2. Grundsätzliches

Bei personenbezogenen Daten handelt es sich um alle Informationen, die " +"sich auf eine identifizierte oder identifizierbare natürliche Person " +"beziehen. Hierzu gehört zum Beispiel dein Name, deine Anschrift, dein " +"Geburtsdatum, deine E-Mail-Adresse oder deine IP-Adresse. Wir speichern und " +"verwenden deine personenbezogenen Daten ausschließlich für die Bearbeitung " +"deiner Aufträge und für die Kontaktaufnahme mit dir.


3. Verarbeitung deiner personenbezogenen Daten

Bei jedem Aufruf einer unserer Internetseiten wird u. a. deine IP-Adresse " +"gespeichert. Wenn du dich bei uns registrierst, werden deine Kontaktdaten " +"gespeichert. Wenn du Aufträge an uns richtest oder Produkte bei uns " +"bestellst, werden darüber hinaus auch deine Anschrift und deine
Zahlungsdaten gespeichert.

I. Registrierungsdaten

Im Rahmen der Registrierung müssen wir einige " +"personenbezogene Daten von dir erheben und verarbeiten. Beispielsweise " +"benötigen wir deinen Namen, deine Anschrift, deine Telefonnummer, deine E-" +"Mail-Adresse und deine Zahlungsdaten um deine Aufträge zu verarbeiten.
Bei der Zahlung mittels Kreditkarte erfassen und speichern wir keine " +"Zahlungsverkehrsinformationen wie Kreditkartennummern, das Ablaufdatum oder " +"die Prüfziffer. Diese gibst du ausschließlich direkt dem entsprechenden " +"Zahlungsdienstleister bekannt. Bei der Bezahlung mit Kreditkarte erfolgt die " +"Abwicklung der Bezahlung durch einen externen Dienstleister.
Für die " +"Kreditkartenzahlung werden deine Angaben direkt vom Diensteanbieter Stripe " +"Payments Europe Ltd. („Stripe“) verarbeitet.

II. " +"Serverlogdateien

Bei jedem Aufruf einer unserer " +"Internetseiten speichern wir automatisch bestimmte Daten. Dazu gehören u. a. " +"deine IP-Adresse, Typ und Version des verwendeten Browsers, Uhrzeit, Datum " +"und die Webseite von der du auf unsere Seite gelangst (sog. „Referer“). " +"Deine IP-Adresse wird bei uns nur anonymisiert gespeichert, sodass ein " +"Personenbezug nicht mehr herstellbar ist. Die Erfassung der Daten zur " +"Bereitstellung unserer Internetseiten und die Speicherung der Daten in den " +"Server Logfiles ist für den Betrieb der Internetseite zwingend erforderlich " +"und dient damit der Wahrung eines berechtigten Interesses unseres " +"Unternehmens. Die Rechtsgrundlage für diese Verarbeitung ist Art. 6. Abs. 1 " +"lit. f DSGVO.


4. Speicherdauer

Sofern die verarbeiteten personenbezogenen Daten für die Durchführung eines " +"ggf.
geschlossenen Vertrages nicht mehr erforderlich sind, werden sie " +"umgehend gelöscht. Jedoch kann es auch nach Abschluss des Vertrags " +"erforderlich sein, personenbezogene Daten von dir zu speichern, um unseren " +"vertraglichen oder gesetzlichen Verpflichtungen nachzukommen.


5. Weitergabe von personenbezogenen Daten

Wir " +"geben deine personenbezogenen Daten grundsätzlich nicht an Dritte weiter, es " +"sei denn:

a) Du erteilst uns hierzu deine ausdrückliche " +"Einwilligung nach Art. 6 Abs. 1 S. 1 lit. a DSGVO.

b) Die " +"Weitergabe der Daten ist gesetzlich zulässig und nach Art. 6. Abs. 1 S. 1 " +"lit b DSGVO zur Erfüllung unserer vertraglichen Pflichten mit Ihnen " +"erforderlich.

c) Für die Weitergabe der Daten besteht nach Art. 6. " +"Abs. 1 S. 1 lit. c DSGVO eine gesetzliche Verpflichtung.

d) Die " +"Weitergabe der Daten ist nach Art. 6. Abs. 1 S. 1 lit. f DSGVO zur Wahrung " +"unserer berechtigten Interessen, sowie zur Geltendmachung, Ausübung oder " +"


6. Cookies, Google Analytics und Twitter

Wir " +"setzen auf unseren Internetseiten sog. „Cookies“ ein. Cookies sind kleine " +"Textdateien, die im Rahmen deines Besuchs einer unserer Internetseiten von " +"uns an den Browser deines Endgeräts gesendet und dort gespeichert werden. " +"Einige Funktionen unseres Angebots können ohne den Einsatz bestimmter " +"Cookies grundsätzlich aus technischen Gründen nicht angeboten werden. Du " +"kannst deinen Browser allerdings so konfigurieren, dass er nur noch " +"bestimmte oder auch gar keine Cookies mehr akzeptiert. Es kann jedoch " +"passieren, dass du dadurch möglicherweise nicht mehr alle Funktionen unserer " +"Internetseiten nutzen kannst.
Andere Cookies ermöglichen es uns hingegen " +"verschiedene Analysen deines Verhaltens oder etwa eine Verbindung zu deinen " +"sozialen Netzwerken aufzubauen. Mithilfe dieser Cookies können wir " +"beispielsweise unser Internetangebot für dich nutzerfreundlicher und " +"effektiver gestalten. Daraus folgt, dass wir auf Grundlage unserer " +"berechtigten Unternehmensinteressen (Optimierung und wirtschaftlicher " +"Betrieb unseres Internetangebots) den Werbeanalysedienst „Google Analytics“ " +"der Google Inc., 1600 Amphitheatre Parkway, Mountainview, CA 94043, " +"Vereinigte Staaten von Amerika („Google“) einsetzen. Google verwendet " +"Cookies. Die durch das Cookie erzeugten Informationen werden an einen Server " +"von Google in den Vereinigten Staaten von Amerika übertragen und dort " +"erhoben und gespeichert. Google nutzt dies Informationen in unserem Auftrag " +"dafür, die Nutzung unseres Internetangebots auszuwerten und Berichte über " +"die Aktivitäten auf unserem Onlineangebot uns gegenüber zu erbringen.
Dabei werden aus den verarbeiteten Daten anonymisierte bzw. pseudonyme " +"Nutzungsprofile einiger Nutzer erstellt. Diese Nutzungsprofile sind nicht " +"auf eine IP-Adresse oder einen spezifischen Nutzer zurückzuführen. Darüber " +"hinaus setzen wir Google Analytics nur mit IP-Anonymisierung ein. Das heißt, " +"dass die IP-Adresse von Google gekürzt wird. Nur in wenigen Ausnahmefällen " +"wird die vollständige IP-Adresse an Google übertragen und dort gekürzt. Du " +"kannst der Verarbeitung von deinen erfassten Daten durch die Installation " +"dieses Browserplugins widersprechen: http://tools.google.com/dlpage/gaoptout?hl=de

Weitere Informationen zur Nutzung der Daten durch Google und " +"weiterführende Widerspruchsmöglichkeiten erhältst du in der " +"Datenschutzerklärung von Google:

https://policies.google.com/technologies/ads

und auf den folgenden Webseiten:

https://" +"www.privacyshield.gov/participant?id=a2zt000000001L5AAI&status=Active

https://" +"adssettings.google.com/authenticated

Die personenbezogenen " +"Daten werden nach 14 Monaten gelöscht oder anonymisiert.
Rechtliche " +"Grundlage hierfür ist Art. 6 Abs. 1 lit. f DSGVO.

Innerhalb unseres " +"Onlineangebots können Funktionen und Inhalte des Dienstes Twitter " +"eingebunden werden. Twitter ist ein Dienst der Twitter Inc., 1355 Market " +"Street, Suite 900, San Francisco, CA 94103, Vereinigte Staaten von Amerika. " +"Hierzu können beispielsweise Inhalte wie Bilder, Videos oder Texte und " +"Schaltflächen gehören. Sofern du Mitglied der Plattform Twitter bist, kann " +"Twitter den Aufruf der Funktionalitäten deinem dortigen Profil zuordnen.
Weitere Informationen zum Datenschutz bei Twitter, findest du in der " +"Datenschutzerklärung von
Twitter unter https://twitter.com/de/privacy.



7. " +"Rechte des Betroffenen

Aus der DSGVO ergeben sich für dich " +"als Betroffener die folgenden Rechte:

a) Du kannst gem. Art. 15 " +"DSGVO Auskunft über deine von uns verarbeiteten personenbezogenen Daten " +"verlangen. Du kannst insbesondere Auskunft über den Zweck der Verarbeitung, " +"die Kategorien der erhobenen personenbezogenen Daten, die Kategorien von " +"Dritten, gegenüber denen deine Daten offengelegt werden und die " +"voraussichtliche Speicherdauer verlangen.

b) Du hast gem. Art. 15 " +"u. Art. 16 DSGVO ein Recht auf Berichtigung, Vervollständigung, Löschung und " +"die Bestimmung von Einschränkungen hinsichtlich der Verarbeitung deiner " +"personenbezogenen Daten.

c) Gemäß Art. 17 DSGVO kannst du von uns " +"die Löschung deiner bei uns gespeicherten personenbezogenen Daten verlangen, " +"soweit die Verarbeitung nicht zur Erfüllung unserer rechtlichen " +"Verpflichtungen, aus Gründen des öffentlichen Interesses oder zur " +"Geltendmachung, Ausübung oder Verteidigung von Rechtsansprüchen erforderlich " +"ist.

d) Gemäß Art. 18 DSGVO kannst du von uns die Einschränkung der " +"Verarbeitung deiner personenbezogenen Daten verlangen, soweit die " +"Richtigkeit der Daten von dir bestritten wird, die Verarbeitung " +"grundsätzlich unrechtmäßig ist oder die Löschung deiner
personenbezogenen Daten durch uns ablehnen, weil du diese zur " +"Geltendmachung, Ausübung oder Verteidigung von Rechtsansprüchen benötigst." +"

e) Gemäß Art. 20 DSGVO kannst du von uns verlangen, dass deine " +"personenbezogenen Daten, die du uns zur Verfügung gestellt hast, in einem " +"strukturierten, maschinenlesbaren und gängigen Format zu erhalten oder du " +"kannst die Übermittlung an eine andere Stelle verlangen.

f) Gemäß " +"Art. 7 Abs. 3 DSGVO kannst du deine erteilte Einwilligung gegenüber uns " +"jederzeit widerrufen. Dies hat zur Folge, dass wir die auf dieser " +"Einwilligung beruhende Datenverarbeitung für die Zukunft nicht mehr " +"fortführen dürfen.

g) Gemäß Art. 77 DSGVO steht dir das Recht zu, " +"dich bei einer Aufsichtsbehörde zu beschweren.


8. " +"Hyperlinks und Haftungsausschluss

Auf unseren " +"Internetseiten befinden sich sog. „Hyperlinks“, also Verbindungen bzw.
Weiterleitungen zu den Internetseiten Dritter. Bei Aktivierung dieser " +"Hyperlinks durch Anklicken, wirst du von unserer Internetseite direkt auf " +"die Internetseite eines Dritten weitergeleitet. Wir können keine " +"Verantwortung für den vertraulichen Umgang deiner Daten auf diesen Webseiten " +"Dritter übernehmen, da wir keinen Einfluss darauf haben, dass diese " +"Unternehmen die Datenschutzbestimmungen der DSGVO einhalten. Wir weisen dich " +"außerdem darauf hin, dass es aufgrund der Struktur des Internets möglich " +"ist, dass die Regelungen des Datenschutzes bzw. der DSGVO von anderen, " +"dritten Personen oder Institutionen die nicht innerhalb unseres " +"Verantwortungsbereichs liegen nicht beachtet werden, oder dass sich spontan, " +"kurzfristig schwerwiegende Sicherheitslücken in verbreiteten Standards und " +"technischen Protokollen auftun, die die Datenintegrität gefährden könnten." +"

\n" +" " + +msgid "Page Header" +msgstr "" + +#, python-format +msgid "No %(verbose_name)s found matching the query" +msgstr "" #~ msgid "Accept" #~ msgstr "Annehmen" @@ -689,3 +836,4 @@ msgstr "" #~ msgid "index/?$" #~ msgstr "index/?$" + From 33aeaf7ddba91ec3edc96637a956382b70596c6d Mon Sep 17 00:00:00 2001 From: "app@dynamicweb-production" Date: Thu, 27 Jul 2023 10:32:46 +0200 Subject: [PATCH 03/60] Increase max_digits for generic product price and vat --- hosting/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hosting/models.py b/hosting/models.py index 48238afe..b51d8616 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -75,8 +75,8 @@ class GenericProduct(AssignPermissionsMixin, models.Model): ) product_description = models.CharField(max_length=500, default="") created_at = models.DateTimeField(auto_now_add=True) - product_price = models.DecimalField(max_digits=6, decimal_places=2) - product_vat = models.DecimalField(max_digits=6, decimal_places=4, default=0) + product_price = models.DecimalField(max_digits=10, decimal_places=2) + product_vat = models.DecimalField(max_digits=10, decimal_places=4, default=0) product_is_subscription = models.BooleanField(default=True) product_subscription_interval = models.CharField( max_length=10, default="month", From c69affc9a13dec2045d2bdea335232ff15f80137 Mon Sep 17 00:00:00 2001 From: "app@dynamicweb-production" Date: Thu, 27 Jul 2023 10:33:40 +0200 Subject: [PATCH 04/60] Add migration --- hosting/migrations/0066_auto_20230727_0812.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 hosting/migrations/0066_auto_20230727_0812.py diff --git a/hosting/migrations/0066_auto_20230727_0812.py b/hosting/migrations/0066_auto_20230727_0812.py new file mode 100644 index 00000000..795b1785 --- /dev/null +++ b/hosting/migrations/0066_auto_20230727_0812.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2023-07-27 08:12 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('hosting', '0065_auto_20201231_1041'), + ] + + operations = [ + migrations.AlterField( + model_name='genericproduct', + name='product_price', + field=models.DecimalField(decimal_places=2, max_digits=10), + ), + migrations.AlterField( + model_name='genericproduct', + name='product_vat', + field=models.DecimalField(decimal_places=4, default=0, max_digits=10), + ), + ] From dc6f5dcc5be6b06739fe634e0820366d46db14fc Mon Sep 17 00:00:00 2001 From: "app@dynamicweb-production" Date: Thu, 16 Nov 2023 19:12:59 +0100 Subject: [PATCH 05/60] add recaptcha coe --- dynamicweb/settings/base.py | 3 +++ utils/forms.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/dynamicweb/settings/base.py b/dynamicweb/settings/base.py index 62fe2897..308c9029 100644 --- a/dynamicweb/settings/base.py +++ b/dynamicweb/settings/base.py @@ -56,6 +56,9 @@ dotenv.load_dotenv("{0}/.env".format(PROJECT_DIR)) from multisite import SiteID +RECAPTCHA_PUBLIC_KEY = env('RECAPTCHA_PUBLIC_KEY') +RECAPTCHA_PRIVATE_KEY = env('RECAPTCHA_PRIVATE_KEY') + UNGLEICH_BLOG_SITE_ID = int_env("UNGLEICH_BLOG_SITE_ID") SITE_ID = SiteID(default=(UNGLEICH_BLOG_SITE_ID if UNGLEICH_BLOG_SITE_ID > 0 else 1)) diff --git a/utils/forms.py b/utils/forms.py index f35c90f4..92b442af 100644 --- a/utils/forms.py +++ b/utils/forms.py @@ -4,6 +4,8 @@ from django.core.mail import EmailMultiAlternatives from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ +from captcha.fields import ReCaptchaField + from membership.models import CustomUser from .models import ContactMessage, BillingAddress, UserBillingAddress @@ -188,6 +190,7 @@ class UserBillingAddressForm(forms.ModelForm): class ContactUsForm(forms.ModelForm): error_css_class = 'autofocus' + captcha = ReCaptchaField() class Meta: model = ContactMessage From 9f74c0286e30d2ac68af477d81eb7183426d83f7 Mon Sep 17 00:00:00 2001 From: "app@dynamicweb-production" Date: Thu, 16 Nov 2023 19:24:59 +0100 Subject: [PATCH 06/60] Add installed app --- dynamicweb/settings/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dynamicweb/settings/base.py b/dynamicweb/settings/base.py index 308c9029..f03042dc 100644 --- a/dynamicweb/settings/base.py +++ b/dynamicweb/settings/base.py @@ -128,6 +128,7 @@ INSTALLED_APPS = ( 'djangocms_file', 'djangocms_picture', 'djangocms_video', + 'django_recaptcha', # 'djangocms_flash', # 'djangocms_googlemap', # 'djangocms_inherit', From c5f8660c5532481fa43b4f2ff23542752548abd0 Mon Sep 17 00:00:00 2001 From: "app@dynamicweb-production" Date: Fri, 17 Nov 2023 03:29:10 +0100 Subject: [PATCH 07/60] Disable all saving of contact us form and send emails --- alplora/views.py | 6 +++--- digitalglarus/views.py | 6 +++--- ungleich_page/views.py | 6 +++--- utils/forms.py | 19 ++++++++++--------- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/alplora/views.py b/alplora/views.py index 0a10b4e0..9fcbbc2f 100644 --- a/alplora/views.py +++ b/alplora/views.py @@ -31,9 +31,9 @@ class ContactView(FormView): return context def form_valid(self, form): - form.save() - form.send_email(email_to='info@alplora.ch') - messages.add_message(self.request, messages.SUCCESS, self.success_message) + #form.save() + #form.send_email(email_to='info@alplora.ch') + #messages.add_message(self.request, messages.SUCCESS, self.success_message) return render(self.request, 'alplora/contact_success.html', {}) diff --git a/digitalglarus/views.py b/digitalglarus/views.py index 299327e6..ba1a59f7 100644 --- a/digitalglarus/views.py +++ b/digitalglarus/views.py @@ -835,9 +835,9 @@ class ContactView(FormView): success_message = _('Message Successfully Sent') def form_valid(self, form): - form.save() - form.send_email() - messages.add_message(self.request, messages.SUCCESS, self.success_message) + #form.save() + #form.send_email() + #messages.add_message(self.request, messages.SUCCESS, self.success_message) return super(ContactView, self).form_valid(form) diff --git a/ungleich_page/views.py b/ungleich_page/views.py index e5a99d8d..372afb86 100644 --- a/ungleich_page/views.py +++ b/ungleich_page/views.py @@ -25,9 +25,9 @@ class ContactView(FormView): success_message = _('Message Successfully Sent') def form_valid(self, form): - form.save() - form.send_email() - messages.add_message(self.request, messages.SUCCESS, self.success_message) + #form.save() + #form.send_email() + #messages.add_message(self.request, messages.SUCCESS, self.success_message) return super(ContactView, self).form_valid(form) def get_context_data(self, **kwargs): diff --git a/utils/forms.py b/utils/forms.py index 92b442af..3cc57578 100644 --- a/utils/forms.py +++ b/utils/forms.py @@ -4,7 +4,7 @@ from django.core.mail import EmailMultiAlternatives from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ -from captcha.fields import ReCaptchaField +from django_recaptcha.fields import ReCaptchaField from membership.models import CustomUser from .models import ContactMessage, BillingAddress, UserBillingAddress @@ -209,11 +209,12 @@ class ContactUsForm(forms.ModelForm): } def send_email(self, email_to='info@digitalglarus.ch'): - text_content = render_to_string( - 'emails/contact.txt', {'data': self.cleaned_data}) - html_content = render_to_string( - 'emails/contact.html', {'data': self.cleaned_data}) - email = EmailMultiAlternatives('Subject', text_content) - email.attach_alternative(html_content, "text/html") - email.to = [email_to] - email.send() + pass + #text_content = render_to_string( + # 'emails/contact.txt', {'data': self.cleaned_data}) + #html_content = render_to_string( + # 'emails/contact.html', {'data': self.cleaned_data}) + #email = EmailMultiAlternatives('Subject', text_content) + #email.attach_alternative(html_content, "text/html") + #email.to = [email_to] + #email.send() From 3c3c614b6b1d0c5993460dd1e21b6f05fb0e2d3c Mon Sep 17 00:00:00 2001 From: "app@dynamicweb-production" Date: Fri, 17 Nov 2023 03:39:12 +0100 Subject: [PATCH 08/60] Debug --- alplora/views.py | 1 + digitalglarus/views.py | 1 + ungleich_page/views.py | 1 + 3 files changed, 3 insertions(+) diff --git a/alplora/views.py b/alplora/views.py index 9fcbbc2f..d628cffc 100644 --- a/alplora/views.py +++ b/alplora/views.py @@ -31,6 +31,7 @@ class ContactView(FormView): return context def form_valid(self, form): + print("alplora contactusform") #form.save() #form.send_email(email_to='info@alplora.ch') #messages.add_message(self.request, messages.SUCCESS, self.success_message) diff --git a/digitalglarus/views.py b/digitalglarus/views.py index ba1a59f7..bf3ed2c6 100644 --- a/digitalglarus/views.py +++ b/digitalglarus/views.py @@ -835,6 +835,7 @@ class ContactView(FormView): success_message = _('Message Successfully Sent') def form_valid(self, form): + print("digital glarus contactusform") #form.save() #form.send_email() #messages.add_message(self.request, messages.SUCCESS, self.success_message) diff --git a/ungleich_page/views.py b/ungleich_page/views.py index 372afb86..01d1138d 100644 --- a/ungleich_page/views.py +++ b/ungleich_page/views.py @@ -25,6 +25,7 @@ class ContactView(FormView): success_message = _('Message Successfully Sent') def form_valid(self, form): + print("ungleich_page contactusform") #form.save() #form.send_email() #messages.add_message(self.request, messages.SUCCESS, self.success_message) From 325d1ffcb94add403cc7c9b60d354d9a16b6ef5e Mon Sep 17 00:00:00 2001 From: "app@dynamicweb-production" Date: Fri, 17 Nov 2023 03:43:49 +0100 Subject: [PATCH 09/60] Ignore more contact f --- datacenterlight/views.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/datacenterlight/views.py b/datacenterlight/views.py index 5bf68e0a..5c333a63 100644 --- a/datacenterlight/views.py +++ b/datacenterlight/views.py @@ -63,23 +63,23 @@ class ContactUsView(FormView): ) def form_valid(self, form): - form.save() - from_emails = { - 'glasfaser': 'glasfaser@ungleich.ch' - } - from_page = self.request.POST.get('from_page') - email_data = { - 'subject': "{dcl_text} Message from {sender}".format( - dcl_text=settings.DCL_TEXT, - sender=form.cleaned_data.get('email') - ), - 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, - 'to': [from_emails.get(from_page, 'support@ungleich.ch')], - 'body': "\n".join( - ["%s=%s" % (k, v) for (k, v) in form.cleaned_data.items()]), - 'reply_to': [form.cleaned_data.get('email')], - } - send_plain_email_task.delay(email_data) + #form.save() + #from_emails = { + # 'glasfaser': 'glasfaser@ungleich.ch' + #} + #from_page = self.request.POST.get('from_page') + #email_data = { + # 'subject': "{dcl_text} Message from {sender}".format( + # dcl_text=settings.DCL_TEXT, + # sender=form.cleaned_data.get('email') + # ), + # 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, + # 'to': [from_emails.get(from_page, 'support@ungleich.ch')], + # 'body': "\n".join( + # ["%s=%s" % (k, v) for (k, v) in form.cleaned_data.items()]), + # 'reply_to': [form.cleaned_data.get('email')], + #} + #send_plain_email_task.delay(email_data) if self.request.is_ajax(): return self.render_to_response( self.get_context_data(success=True, contact_form=form)) From a492c3de1bbccab4553ab268a7e8156d1cc51329 Mon Sep 17 00:00:00 2001 From: PCoder Date: Wed, 6 Dec 2023 15:34:23 +0530 Subject: [PATCH 10/60] Add management command --- .../commands/change_ch_vatrate_2023.py | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 hosting/management/commands/change_ch_vatrate_2023.py diff --git a/hosting/management/commands/change_ch_vatrate_2023.py b/hosting/management/commands/change_ch_vatrate_2023.py new file mode 100644 index 00000000..568ba78c --- /dev/null +++ b/hosting/management/commands/change_ch_vatrate_2023.py @@ -0,0 +1,93 @@ +from django.core.management.base import BaseCommand +import datetime +import csv +import stripe +from hosting.models import VATRates +from utils.hosting_utils import get_vat_rate_for_country +from django.conf import settings + +stripe.api_key = settings.STRIPE_API_PRIVATE_KEY + + +class Command(BaseCommand): + help = '''CH vat rate changes on 2024-01-01 from 7.7% to 8.1%. This commands makes the necessary changes''' + + def handle(self, *args, **options): + MAKE_MODIFS=False + try: + country_to_change = 'CH' + currency_to_change = 'CHF' + new_rate = 0.081 + user_country_vat_rate = get_vat_rate_for_country(country_to_change) + logger.debug("Existing VATRate for %s %s " % (country_to_change, user_country_vat_rate)) + vat_rate = VATRates.objects.get( + territory_codes=country_to_change, start_date__isnull=False, stop_date=None + ) + logger.debug("VAT rate for %s is %s" % (country, vat_rate.rate)) + logger.debug("vat_rate object = %s" % vat_rate) + logger.debug("Create end date for the VATRate %s" % vat_rate.id) + if MAKE_MODIFS: + vat_rate.stop_date = datetime.date(2023, 12, 31) + vat_rate.save() + print("Creating a new VATRate for CH") + obj, created = VATRates.objects.get_or_create( + start_date=datetime.date(2024, 1, 1), + stop_date=None, + territory_codes=country_to_change, + currency_code=currency_to_change, + rate=new_rate, + rate_type="standard", + description="Switzerland standard VAT (added manually on %s)" % datetime.datetime.now() + ) + if created: + logger.debug("Created new VAT Rate for %s with the new rate %s" % (country_to_change, new_rate)) + logger.debug(obj) + else: + logger.debug("VAT Rate for %s already exists with the rate %s" % (country_to_change, new_rate)) + + logger.debug("Getting all subscriptions of %s that need a VAT Rate change") + subscriptions = stripe.Subscription.list(limit=100) # Increase the limit to 100 per page (maximum) + ch_subs = [] + + while subscriptions: + for subscription in subscriptions: + if len(subscription.default_tax_rates) > 0 and subscription.default_tax_rates[0].jurisdiction and subscription.default_tax_rates[0].jurisdiction.lower() == 'ch': + ch_subs.append(subscription) + elif len(subscription.default_tax_rates) > 0: + print("subscription %s belongs to %s" % (subscription.id, subscription.default_tax_rates[0].jurisdiction)) + else: + print("subscription %s does not have a tax rate" % subscription.id) + if subscriptions.has_more: + print("FETCHING MORE") + subscriptions = stripe.Subscription.list(limit=100, starting_after=subscriptions.data[-1]) + else: + break + logger.debug("There are %s ch subscription that need VAT rate update" % len(ch_subs)) + + if MAKE_MODIFS: + print("Making modifications now") + tax_rate_obj = stripe.TaxRate.create( + display_name="VAT", + description="VAT for %s" % country_to_change, + jurisdiction=country_to_change, + percentage=new_rate, + inclusive=False, + ) + stripe_tax_rate = StripeTaxRate.objects.create( + display_name=tax_rate_obj.display_name, + description=tax_rate_obj.description, + jurisdiction=tax_rate_obj.jurisdiction, + percentage=tax_rate_obj.percentage, + inclusive=False, + tax_rate_id=tax_rate_obj.id + ) + + for ch_sub in ch_subs: + ch_sub.default_tax_rates = [stripe_tax_rate.tax_rate_id] + ch_sub.save() + logger.debug("Default tax rate updated for %s" % ch_sub.id) + else: + print("Not making any modifications because MAKE_MODIFS=False") + + except Exception as e: + print(" *** Error occurred. Details {}".format(str(e))) From 5530b48d0dedff5dfc5901fbf6e815fb4fdb6a75 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 25 Dec 2023 11:23:01 +0530 Subject: [PATCH 11/60] Save subscriptions to be changed in a csv --- .../commands/change_ch_vatrate_2023.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/hosting/management/commands/change_ch_vatrate_2023.py b/hosting/management/commands/change_ch_vatrate_2023.py index 568ba78c..2740be9c 100644 --- a/hosting/management/commands/change_ch_vatrate_2023.py +++ b/hosting/management/commands/change_ch_vatrate_2023.py @@ -64,6 +64,44 @@ class Command(BaseCommand): break logger.debug("There are %s ch subscription that need VAT rate update" % len(ch_subs)) + # CSV column headers + csv_headers = [ + "customer_name", + "subscription_id", + "subscription_name", + "amount", + "vat_rate" + ] + # CSV file name + csv_filename = "ch_subscriptions_change_2024.csv" + # Write subscription data to CSV file + with open(csv_filename, mode='w', newline='') as csv_file: + writer = csv.DictWriter(csv_file, fieldnames=csv_headers) + writer.writeheader() + + for subscription in subscriptions: + subscription_id = subscription["id"] + customer_name = subscription.get("customer", "") + items = subscription.get("items", {}).get("data", []) + + for item in items: + subscription_name = item.get("plan", {}).get("id", "") + amount = item.get("plan", {}).get("amount", "") + vat_rates = item.get("tax_rates", []) + + # Convert amount to a proper format (e.g., cents to dollars) + amount_in_chf = amount / 100 # Adjust this conversion as needed + + # Writing to CSV + writer.writerow({ + "customer_name": customer_name, + "subscription_id": subscription_id, + "subscription_name": subscription_name, + "amount": amount_in_chf, + "vat_rate": ", ".join(vat_rates) # Fill in VAT rate if available + }) + + if MAKE_MODIFS: print("Making modifications now") tax_rate_obj = stripe.TaxRate.create( From ea4ff961c2eb149bb3f469a6690d939881a8e017 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 25 Dec 2023 11:43:29 +0530 Subject: [PATCH 12/60] add missing logging --- hosting/management/commands/change_ch_vatrate_2023.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hosting/management/commands/change_ch_vatrate_2023.py b/hosting/management/commands/change_ch_vatrate_2023.py index 2740be9c..d6e2ef05 100644 --- a/hosting/management/commands/change_ch_vatrate_2023.py +++ b/hosting/management/commands/change_ch_vatrate_2023.py @@ -1,6 +1,7 @@ from django.core.management.base import BaseCommand import datetime import csv +import logging import stripe from hosting.models import VATRates from utils.hosting_utils import get_vat_rate_for_country @@ -8,6 +9,7 @@ from django.conf import settings stripe.api_key = settings.STRIPE_API_PRIVATE_KEY +logger = logging.getLogger(__name__) class Command(BaseCommand): help = '''CH vat rate changes on 2024-01-01 from 7.7% to 8.1%. This commands makes the necessary changes''' From a0ade926fb71955435b5c42eae26b76095d55025 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 25 Dec 2023 11:44:52 +0530 Subject: [PATCH 13/60] Fix variable name typo --- hosting/management/commands/change_ch_vatrate_2023.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosting/management/commands/change_ch_vatrate_2023.py b/hosting/management/commands/change_ch_vatrate_2023.py index d6e2ef05..43cb1d92 100644 --- a/hosting/management/commands/change_ch_vatrate_2023.py +++ b/hosting/management/commands/change_ch_vatrate_2023.py @@ -25,7 +25,7 @@ class Command(BaseCommand): vat_rate = VATRates.objects.get( territory_codes=country_to_change, start_date__isnull=False, stop_date=None ) - logger.debug("VAT rate for %s is %s" % (country, vat_rate.rate)) + logger.debug("VAT rate for %s is %s" % (country_to_change, vat_rate.rate)) logger.debug("vat_rate object = %s" % vat_rate) logger.debug("Create end date for the VATRate %s" % vat_rate.id) if MAKE_MODIFS: From 92e525467968bbf7f9d7156f5ca6c541d89a0565 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 25 Dec 2023 12:14:48 +0530 Subject: [PATCH 14/60] Fix customer name and vat rate --- .../management/commands/change_ch_vatrate_2023.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/hosting/management/commands/change_ch_vatrate_2023.py b/hosting/management/commands/change_ch_vatrate_2023.py index 43cb1d92..cbf77060 100644 --- a/hosting/management/commands/change_ch_vatrate_2023.py +++ b/hosting/management/commands/change_ch_vatrate_2023.py @@ -6,6 +6,7 @@ import stripe from hosting.models import VATRates from utils.hosting_utils import get_vat_rate_for_country from django.conf import settings +from membership.models import CustomUser, StripeCustomer stripe.api_key = settings.STRIPE_API_PRIVATE_KEY @@ -81,15 +82,17 @@ class Command(BaseCommand): writer = csv.DictWriter(csv_file, fieldnames=csv_headers) writer.writeheader() - for subscription in subscriptions: + for subscription in ch_subs: subscription_id = subscription["id"] - customer_name = subscription.get("customer", "") + stripe_customer_id = subscription.get("customer", "") + vat_rate = subscription.get("tax_percent", "") + c_user = CustomUser.objects.get( + id=StripeCustomer.objects.filter(stripe_id=stripe_customer_id)[0].id) + customer_name = "%s - %s - %s" % (c_user.name, c_user.email, stripe_customer_id) items = subscription.get("items", {}).get("data", []) - for item in items: subscription_name = item.get("plan", {}).get("id", "") amount = item.get("plan", {}).get("amount", "") - vat_rates = item.get("tax_rates", []) # Convert amount to a proper format (e.g., cents to dollars) amount_in_chf = amount / 100 # Adjust this conversion as needed @@ -100,7 +103,7 @@ class Command(BaseCommand): "subscription_id": subscription_id, "subscription_name": subscription_name, "amount": amount_in_chf, - "vat_rate": ", ".join(vat_rates) # Fill in VAT rate if available + "vat_rate": vat_rate # Fill in VAT rate if available }) From f31838dbe5189c434e7c35e831185b044ccc7eee Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 25 Dec 2023 12:22:34 +0530 Subject: [PATCH 15/60] Separate fields --- hosting/management/commands/change_ch_vatrate_2023.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hosting/management/commands/change_ch_vatrate_2023.py b/hosting/management/commands/change_ch_vatrate_2023.py index cbf77060..45ec70d9 100644 --- a/hosting/management/commands/change_ch_vatrate_2023.py +++ b/hosting/management/commands/change_ch_vatrate_2023.py @@ -88,7 +88,8 @@ class Command(BaseCommand): vat_rate = subscription.get("tax_percent", "") c_user = CustomUser.objects.get( id=StripeCustomer.objects.filter(stripe_id=stripe_customer_id)[0].id) - customer_name = "%s - %s - %s" % (c_user.name, c_user.email, stripe_customer_id) + customer_name = c_user.name.encode('utf-8') + customer_email = c.user_email items = subscription.get("items", {}).get("data", []) for item in items: subscription_name = item.get("plan", {}).get("id", "") @@ -100,6 +101,8 @@ class Command(BaseCommand): # Writing to CSV writer.writerow({ "customer_name": customer_name, + "customer_email": customer_email, + "stripe_customer_id": stripe_customer_id, "subscription_id": subscription_id, "subscription_name": subscription_name, "amount": amount_in_chf, From 10c167e76bdf3e5e76e4fe2b68498750e195ac18 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 25 Dec 2023 12:23:52 +0530 Subject: [PATCH 16/60] Fix typo --- hosting/management/commands/change_ch_vatrate_2023.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosting/management/commands/change_ch_vatrate_2023.py b/hosting/management/commands/change_ch_vatrate_2023.py index 45ec70d9..f979ad71 100644 --- a/hosting/management/commands/change_ch_vatrate_2023.py +++ b/hosting/management/commands/change_ch_vatrate_2023.py @@ -89,7 +89,7 @@ class Command(BaseCommand): c_user = CustomUser.objects.get( id=StripeCustomer.objects.filter(stripe_id=stripe_customer_id)[0].id) customer_name = c_user.name.encode('utf-8') - customer_email = c.user_email + customer_email = c_user.user_email items = subscription.get("items", {}).get("data", []) for item in items: subscription_name = item.get("plan", {}).get("id", "") From 3c4881154898438a740be13397ba84563850696d Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 25 Dec 2023 12:25:07 +0530 Subject: [PATCH 17/60] Fix typo --- hosting/management/commands/change_ch_vatrate_2023.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosting/management/commands/change_ch_vatrate_2023.py b/hosting/management/commands/change_ch_vatrate_2023.py index f979ad71..f96b36d2 100644 --- a/hosting/management/commands/change_ch_vatrate_2023.py +++ b/hosting/management/commands/change_ch_vatrate_2023.py @@ -89,7 +89,7 @@ class Command(BaseCommand): c_user = CustomUser.objects.get( id=StripeCustomer.objects.filter(stripe_id=stripe_customer_id)[0].id) customer_name = c_user.name.encode('utf-8') - customer_email = c_user.user_email + customer_email = c_user.email items = subscription.get("items", {}).get("data", []) for item in items: subscription_name = item.get("plan", {}).get("id", "") From 36b091700e643a4efe79af0e61514bc6aa4455e3 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 25 Dec 2023 12:28:03 +0530 Subject: [PATCH 18/60] Fix headers --- hosting/management/commands/change_ch_vatrate_2023.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hosting/management/commands/change_ch_vatrate_2023.py b/hosting/management/commands/change_ch_vatrate_2023.py index f96b36d2..93920904 100644 --- a/hosting/management/commands/change_ch_vatrate_2023.py +++ b/hosting/management/commands/change_ch_vatrate_2023.py @@ -70,6 +70,8 @@ class Command(BaseCommand): # CSV column headers csv_headers = [ "customer_name", + "customer_email", + "stripe_customer_id", "subscription_id", "subscription_name", "amount", From 94a81fc976243a4847fda83a50fa56b0f6d31c1c Mon Sep 17 00:00:00 2001 From: PCoder Date: Wed, 27 Dec 2023 19:49:50 +0530 Subject: [PATCH 19/60] Fix obtaining correct CustomUSer --- hosting/management/commands/change_ch_vatrate_2023.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosting/management/commands/change_ch_vatrate_2023.py b/hosting/management/commands/change_ch_vatrate_2023.py index 93920904..e397a208 100644 --- a/hosting/management/commands/change_ch_vatrate_2023.py +++ b/hosting/management/commands/change_ch_vatrate_2023.py @@ -89,7 +89,7 @@ class Command(BaseCommand): stripe_customer_id = subscription.get("customer", "") vat_rate = subscription.get("tax_percent", "") c_user = CustomUser.objects.get( - id=StripeCustomer.objects.filter(stripe_id=stripe_customer_id)[0].id) + id=StripeCustomer.objects.filter(stripe_id=stripe_customer_id)[0].user.id) customer_name = c_user.name.encode('utf-8') customer_email = c_user.email items = subscription.get("items", {}).get("data", []) From 4d3da3387ae7d53fa3e1383ef0bce784d6b6d00f Mon Sep 17 00:00:00 2001 From: PCoder Date: Wed, 27 Dec 2023 20:36:59 +0530 Subject: [PATCH 20/60] Print case where CustomUser is not found in the datbase from Stripe customer id --- .../commands/change_ch_vatrate_2023.py | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/hosting/management/commands/change_ch_vatrate_2023.py b/hosting/management/commands/change_ch_vatrate_2023.py index e397a208..46ca2312 100644 --- a/hosting/management/commands/change_ch_vatrate_2023.py +++ b/hosting/management/commands/change_ch_vatrate_2023.py @@ -90,26 +90,29 @@ class Command(BaseCommand): vat_rate = subscription.get("tax_percent", "") c_user = CustomUser.objects.get( id=StripeCustomer.objects.filter(stripe_id=stripe_customer_id)[0].user.id) - customer_name = c_user.name.encode('utf-8') - customer_email = c_user.email - items = subscription.get("items", {}).get("data", []) - for item in items: - subscription_name = item.get("plan", {}).get("id", "") - amount = item.get("plan", {}).get("amount", "") + if c_user: + customer_name = c_user.name.encode('utf-8') + customer_email = c_user.email + items = subscription.get("items", {}).get("data", []) + for item in items: + subscription_name = item.get("plan", {}).get("id", "") + amount = item.get("plan", {}).get("amount", "") - # Convert amount to a proper format (e.g., cents to dollars) - amount_in_chf = amount / 100 # Adjust this conversion as needed + # Convert amount to a proper format (e.g., cents to dollars) + amount_in_chf = amount / 100 # Adjust this conversion as needed - # Writing to CSV - writer.writerow({ - "customer_name": customer_name, - "customer_email": customer_email, - "stripe_customer_id": stripe_customer_id, - "subscription_id": subscription_id, - "subscription_name": subscription_name, - "amount": amount_in_chf, - "vat_rate": vat_rate # Fill in VAT rate if available - }) + # Writing to CSV + writer.writerow({ + "customer_name": customer_name, + "customer_email": customer_email, + "stripe_customer_id": stripe_customer_id, + "subscription_id": subscription_id, + "subscription_name": subscription_name, + "amount": amount_in_chf, + "vat_rate": vat_rate # Fill in VAT rate if available + }) + else: + print("No customuser for %s %s" % (stripe_customer_id, subscription_id)) if MAKE_MODIFS: From 4e891ed0bbcd8602402521a939cfc0797bb39f28 Mon Sep 17 00:00:00 2001 From: PCoder Date: Fri, 29 Dec 2023 08:50:58 +0530 Subject: [PATCH 21/60] Update countries list --- utils/fields.py | 88 ++++++++++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 38 deletions(-) diff --git a/utils/fields.py b/utils/fields.py index 48a606cc..ca1115de 100644 --- a/utils/fields.py +++ b/utils/fields.py @@ -1,7 +1,8 @@ from django.utils.translation import ugettext as _ from django.db import models -# http://xml.coverpages.org/country3166.html +# Old: http://xml.coverpages.org/country3166.html +# 2023-12-29: Updated list of countries from https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes COUNTRIES = ( ('AD', _('Andorra')), ('AE', _('United Arab Emirates')), @@ -10,7 +11,6 @@ COUNTRIES = ( ('AI', _('Anguilla')), ('AL', _('Albania')), ('AM', _('Armenia')), - ('AN', _('Netherlands Antilles')), ('AO', _('Angola')), ('AQ', _('Antarctica')), ('AR', _('Argentina')), @@ -18,6 +18,7 @@ COUNTRIES = ( ('AT', _('Austria')), ('AU', _('Australia')), ('AW', _('Aruba')), + ('AX', _('Aland Islands')), ('AZ', _('Azerbaijan')), ('BA', _('Bosnia and Herzegovina')), ('BB', _('Barbados')), @@ -28,11 +29,13 @@ COUNTRIES = ( ('BH', _('Bahrain')), ('BI', _('Burundi')), ('BJ', _('Benin')), + ('BL', _('St. Barts')), ('BM', _('Bermuda')), - ('BN', _('Brunei Darussalam')), + ('BN', _('Brunei')), ('BO', _('Bolivia')), + ('BQ', _('Caribbean Netherlands')), ('BR', _('Brazil')), - ('BS', _('Bahama')), + ('BS', _('Bahamas')), ('BT', _('Bhutan')), ('BV', _('Bouvet Island')), ('BW', _('Botswana')), @@ -40,11 +43,12 @@ COUNTRIES = ( ('BZ', _('Belize')), ('CA', _('Canada')), ('CC', _('Cocos (Keeling) Islands')), + ('CD', _('Congo - Kinshasa')), ('CF', _('Central African Republic')), - ('CG', _('Congo')), + ('CG', _('Congo - Brazzaville')), ('CH', _('Switzerland')), ('CI', _('Ivory Coast')), - ('CK', _('Cook Iislands')), + ('CK', _('Cook Islands')), ('CL', _('Chile')), ('CM', _('Cameroon')), ('CN', _('China')), @@ -52,9 +56,10 @@ COUNTRIES = ( ('CR', _('Costa Rica')), ('CU', _('Cuba')), ('CV', _('Cape Verde')), + ('CW', _('Curacao')), ('CX', _('Christmas Island')), ('CY', _('Cyprus')), - ('CZ', _('Czech Republic')), + ('CZ', _('Czechia')), ('DE', _('Germany')), ('DJ', _('Djibouti')), ('DK', _('Denmark')), @@ -70,16 +75,16 @@ COUNTRIES = ( ('ET', _('Ethiopia')), ('FI', _('Finland')), ('FJ', _('Fiji')), - ('FK', _('Falkland Islands (Malvinas)')), + ('FK', _('Falkland Islands')), ('FM', _('Micronesia')), ('FO', _('Faroe Islands')), ('FR', _('France')), - ('FX', _('France, Metropolitan')), ('GA', _('Gabon')), - ('GB', _('United Kingdom (Great Britain)')), + ('GB', _('United Kingdom')), ('GD', _('Grenada')), ('GE', _('Georgia')), ('GF', _('French Guiana')), + ('GG', _('Guernsey')), ('GH', _('Ghana')), ('GI', _('Gibraltar')), ('GL', _('Greenland')), @@ -93,7 +98,7 @@ COUNTRIES = ( ('GU', _('Guam')), ('GW', _('Guinea-Bissau')), ('GY', _('Guyana')), - ('HK', _('Hong Kong')), + ('HK', _('Hong Kong SAR China')), ('HM', _('Heard & McDonald Islands')), ('HN', _('Honduras')), ('HR', _('Croatia')), @@ -102,12 +107,14 @@ COUNTRIES = ( ('ID', _('Indonesia')), ('IE', _('Ireland')), ('IL', _('Israel')), + ('IM', _('Isle of Man')), ('IN', _('India')), ('IO', _('British Indian Ocean Territory')), ('IQ', _('Iraq')), - ('IR', _('Islamic Republic of Iran')), + ('IR', _('Iran')), ('IS', _('Iceland')), ('IT', _('Italy')), + ('JE', _('Jersey')), ('JM', _('Jamaica')), ('JO', _('Jordan')), ('JP', _('Japan')), @@ -117,14 +124,14 @@ COUNTRIES = ( ('KI', _('Kiribati')), ('KM', _('Comoros')), ('KN', _('St. Kitts and Nevis')), - ('KP', _('Korea, Democratic People\'s Republic of')), - ('KR', _('Korea, Republic of')), + ('KP', _('North Korea')), + ('KR', _('South Korea')), ('KW', _('Kuwait')), ('KY', _('Cayman Islands')), ('KZ', _('Kazakhstan')), - ('LA', _('Lao People\'s Democratic Republic')), + ('LA', _('Laos')), ('LB', _('Lebanon')), - ('LC', _('Saint Lucia')), + ('LC', _('St. Lucia')), ('LI', _('Liechtenstein')), ('LK', _('Sri Lanka')), ('LR', _('Liberia')), @@ -132,20 +139,23 @@ COUNTRIES = ( ('LT', _('Lithuania')), ('LU', _('Luxembourg')), ('LV', _('Latvia')), - ('LY', _('Libyan Arab Jamahiriya')), + ('LY', _('Libya')), ('MA', _('Morocco')), ('MC', _('Monaco')), - ('MD', _('Moldova, Republic of')), + ('MD', _('Moldova')), + ('ME', _('Montenegro')), + ('MF', _('St. Martin')), ('MG', _('Madagascar')), ('MH', _('Marshall Islands')), + ('MK', _('North Macedonia')), ('ML', _('Mali')), + ('MM', _('Myanmar (Burma)')), ('MN', _('Mongolia')), - ('MM', _('Myanmar')), - ('MO', _('Macau')), + ('MO', _('Macao SAR China')), ('MP', _('Northern Mariana Islands')), ('MQ', _('Martinique')), ('MR', _('Mauritania')), - ('MS', _('Monserrat')), + ('MS', _('Montserrat')), ('MT', _('Malta')), ('MU', _('Mauritius')), ('MV', _('Maldives')), @@ -174,15 +184,17 @@ COUNTRIES = ( ('PK', _('Pakistan')), ('PL', _('Poland')), ('PM', _('St. Pierre & Miquelon')), - ('PN', _('Pitcairn')), + ('PN', _('Pitcairn Islands')), ('PR', _('Puerto Rico')), + ('PS', _('Palestinian Territories')), ('PT', _('Portugal')), ('PW', _('Palau')), ('PY', _('Paraguay')), ('QA', _('Qatar')), ('RE', _('Reunion')), ('RO', _('Romania')), - ('RU', _('Russian Federation')), + ('RS', _('Serbia')), + ('RU', _('Russia')), ('RW', _('Rwanda')), ('SA', _('Saudi Arabia')), ('SB', _('Solomon Islands')), @@ -192,17 +204,19 @@ COUNTRIES = ( ('SG', _('Singapore')), ('SH', _('St. Helena')), ('SI', _('Slovenia')), - ('SJ', _('Svalbard & Jan Mayen Islands')), + ('SJ', _('Svalbard and Jan Mayen')), ('SK', _('Slovakia')), ('SL', _('Sierra Leone')), ('SM', _('San Marino')), ('SN', _('Senegal')), ('SO', _('Somalia')), ('SR', _('Suriname')), + ('SS', _('South Sudan')), ('ST', _('Sao Tome & Principe')), ('SV', _('El Salvador')), - ('SY', _('Syrian Arab Republic')), - ('SZ', _('Swaziland')), + ('SX', _('Sint Maarten')), + ('SY', _('Syria')), + ('SZ', _('Eswatini')), ('TC', _('Turks & Caicos Islands')), ('TD', _('Chad')), ('TF', _('French Southern Territories')), @@ -210,36 +224,34 @@ COUNTRIES = ( ('TH', _('Thailand')), ('TJ', _('Tajikistan')), ('TK', _('Tokelau')), + ('TL', _('Timor-Leste')), ('TM', _('Turkmenistan')), ('TN', _('Tunisia')), ('TO', _('Tonga')), - ('TP', _('East Timor')), ('TR', _('Turkey')), ('TT', _('Trinidad & Tobago')), ('TV', _('Tuvalu')), - ('TW', _('Taiwan, Province of China')), - ('TZ', _('Tanzania, United Republic of')), + ('TW', _('Taiwan')), + ('TZ', _('Tanzania')), ('UA', _('Ukraine')), ('UG', _('Uganda')), - ('UM', _('United States Minor Outlying Islands')), - ('US', _('United States of America')), + ('UM', _('U.S. Outlying Islands')), + ('US', _('United States')), ('UY', _('Uruguay')), ('UZ', _('Uzbekistan')), - ('VA', _('Vatican City State (Holy See)')), - ('VC', _('St. Vincent & the Grenadines')), + ('VA', _('Vatican City')), + ('VC', _('St. Vincent & Grenadines')), ('VE', _('Venezuela')), ('VG', _('British Virgin Islands')), - ('VI', _('United States Virgin Islands')), - ('VN', _('Viet Nam')), + ('VI', _('U.S. Virgin Islands')), + ('VN', _('Vietnam')), ('VU', _('Vanuatu')), - ('WF', _('Wallis & Futuna Islands')), + ('WF', _('Wallis & Futuna')), ('WS', _('Samoa')), ('YE', _('Yemen')), ('YT', _('Mayotte')), - ('YU', _('Yugoslavia')), ('ZA', _('South Africa')), ('ZM', _('Zambia')), - ('ZR', _('Zaire')), ('ZW', _('Zimbabwe')), ) From 83d1e54137673f694a7b5044f695e9904a272e2a Mon Sep 17 00:00:00 2001 From: PCoder Date: Fri, 26 Jan 2024 09:11:57 +0530 Subject: [PATCH 22/60] Fix error when user accesses vm details and no invoices --- hosting/templates/hosting/virtual_machine_detail.html | 2 +- hosting/views.py | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/hosting/templates/hosting/virtual_machine_detail.html b/hosting/templates/hosting/virtual_machine_detail.html index 24b2c6ad..6b41af95 100644 --- a/hosting/templates/hosting/virtual_machine_detail.html +++ b/hosting/templates/hosting/virtual_machine_detail.html @@ -46,7 +46,7 @@
{% trans "Current Pricing" %}
{{order.price|floatformat:2|intcomma}} CHF/{% if order.generic_product %}{% trans order.generic_product.product_subscription_interval %}{% else %}{% trans "Month" %}{% endif %}
- {% trans "See Invoice" %} + {% if inv_url %}{% trans "See Invoice" %}{%else%}{% trans "No invoice as of now" %}{% endif %}
diff --git a/hosting/views.py b/hosting/views.py index e2f6e13b..6b93fdb4 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -1694,7 +1694,11 @@ class VirtualMachineView(LoginRequiredMixin, View): login_url = reverse_lazy('hosting:login') def get_object(self): - owner = self.request.user + username = self.request.GET.get('username') + if self.request.user.is_admin and username: + owner = CustomUser.objects.get(username=username) + else: + owner = self.request.user vm = None manager = OpenNebulaManager( email=owner.username, @@ -1750,7 +1754,10 @@ class VirtualMachineView(LoginRequiredMixin, View): subscription=hosting_order.subscription_id, count=1 ) - inv_url = stripe_obj.data[0].hosted_invoice_url + if stripe_obj.data: + inv_url = stripe_obj.data[0].hosted_invoice_url + else: + inv_url = '' elif hosting_order.stripe_charge_id: stripe_obj = stripe.Charge.retrieve( hosting_order.stripe_charge_id From 96af882e6ddf3160c77d719d14ec062a6cec4c7e Mon Sep 17 00:00:00 2001 From: PCoder Date: Fri, 9 Feb 2024 21:03:17 +0530 Subject: [PATCH 23/60] Fix mistake is obtaining the correct hosting order id --- hosting/templates/hosting/invoices.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosting/templates/hosting/invoices.html b/hosting/templates/hosting/invoices.html index 347b1ff4..69ed4577 100644 --- a/hosting/templates/hosting/invoices.html +++ b/hosting/templates/hosting/invoices.html @@ -87,7 +87,7 @@ {% for ho, stripe_charge_data in invs_charge %} - {{ ho.id | get_line_item_from_hosting_order_charge }} + {{ ho | get_line_item_from_hosting_order_charge }} {% endfor %} From 7afa9d2f4c10115cfce7b07b5a095ccaf9f52c0d Mon Sep 17 00:00:00 2001 From: "app@dynamicweb-production" Date: Fri, 9 Feb 2024 16:37:34 +0100 Subject: [PATCH 24/60] Show settings view for admin --- hosting/views.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/hosting/views.py b/hosting/views.py index 6b93fdb4..3ac8c023 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -554,14 +554,23 @@ class SettingsView(LoginRequiredMixin, FormView): Check if the user already saved contact details. If so, then show the form populated with those details, to let user change them. """ + username = self.request.GET.get('username') + if self.request.user.is_admin and username: + user = CustomUser.objects.get(username=username) + else: + user = self.request.user return form_class( - instance=self.request.user.billing_addresses.first(), + instance=user.billing_addresses.first(), **self.get_form_kwargs()) def get_context_data(self, **kwargs): context = super(SettingsView, self).get_context_data(**kwargs) # Get user - user = self.request.user + username = self.request.GET.get('username') + if self.request.user.is_admin and username: + user = CustomUser.objects.get(username=username) + else: + user = self.request.user stripe_customer = None if hasattr(user, 'stripecustomer'): stripe_customer = user.stripecustomer From 41461538a3c8480fb5650026ef3ce1fbead0f637 Mon Sep 17 00:00:00 2001 From: "app@dynamicweb-production" Date: Fri, 9 Feb 2024 16:38:10 +0100 Subject: [PATCH 25/60] Changes on prod --- .../commands/change_ch_vatrate_2023.py | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/hosting/management/commands/change_ch_vatrate_2023.py b/hosting/management/commands/change_ch_vatrate_2023.py index 46ca2312..612b246e 100644 --- a/hosting/management/commands/change_ch_vatrate_2023.py +++ b/hosting/management/commands/change_ch_vatrate_2023.py @@ -29,25 +29,25 @@ class Command(BaseCommand): logger.debug("VAT rate for %s is %s" % (country_to_change, vat_rate.rate)) logger.debug("vat_rate object = %s" % vat_rate) logger.debug("Create end date for the VATRate %s" % vat_rate.id) - if MAKE_MODIFS: - vat_rate.stop_date = datetime.date(2023, 12, 31) - vat_rate.save() - print("Creating a new VATRate for CH") - obj, created = VATRates.objects.get_or_create( - start_date=datetime.date(2024, 1, 1), - stop_date=None, - territory_codes=country_to_change, - currency_code=currency_to_change, - rate=new_rate, - rate_type="standard", - description="Switzerland standard VAT (added manually on %s)" % datetime.datetime.now() - ) - if created: - logger.debug("Created new VAT Rate for %s with the new rate %s" % (country_to_change, new_rate)) - logger.debug(obj) - else: - logger.debug("VAT Rate for %s already exists with the rate %s" % (country_to_change, new_rate)) - + # if MAKE_MODIFS: + # vat_rate.stop_date = datetime.date(2023, 12, 31) + # vat_rate.save() + # print("Creating a new VATRate for CH") + # obj, created = VATRates.objects.get_or_create( + # start_date=datetime.date(2024, 1, 1), + # stop_date=None, + # territory_codes=country_to_change, + # currency_code=currency_to_change, + # rate=new_rate, + # rate_type="standard", + # description="Switzerland standard VAT (added manually on %s)" % datetime.datetime.now() + # ) + # if created: + # logger.debug("Created new VAT Rate for %s with the new rate %s" % (country_to_change, new_rate)) + # logger.debug(obj) + # else: + # logger.debug("VAT Rate for %s already exists with the rate %s" % (country_to_change, new_rate)) + # logger.debug("Getting all subscriptions of %s that need a VAT Rate change") subscriptions = stripe.Subscription.list(limit=100) # Increase the limit to 100 per page (maximum) ch_subs = [] From 10d2c25556ca6138107267a063cdf1ee17994cef Mon Sep 17 00:00:00 2001 From: PCoder Date: Fri, 16 Feb 2024 16:23:02 +0530 Subject: [PATCH 26/60] Get product name from id it starts with generic otherwise use as is --- datacenterlight/templatetags/custom_tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datacenterlight/templatetags/custom_tags.py b/datacenterlight/templatetags/custom_tags.py index 120cabbf..5d0c01b3 100644 --- a/datacenterlight/templatetags/custom_tags.py +++ b/datacenterlight/templatetags/custom_tags.py @@ -144,7 +144,7 @@ def get_line_item_from_stripe_invoice(invoice): """.format( vm_id=vm_id if vm_id > 0 else "", ip_addresses=mark_safe(get_ip_addresses(vm_id)) if vm_id > 0 else - mark_safe(get_product_name(plan_name)), + mark_safe(get_product_name(plan_name)) if plan_name.startswith("generic-") else plan_name, period=mark_safe("%s — %s" % ( datetime.datetime.fromtimestamp(start_date).strftime('%Y-%m-%d'), datetime.datetime.fromtimestamp(end_date).strftime('%Y-%m-%d'))), From 6a374f7fa0010ef62def8bbed09151b6b69ad60b Mon Sep 17 00:00:00 2001 From: PCoder Date: Fri, 16 Feb 2024 16:23:19 +0530 Subject: [PATCH 27/60] Rearrange --- datacenterlight/templatetags/custom_tags.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/datacenterlight/templatetags/custom_tags.py b/datacenterlight/templatetags/custom_tags.py index 5d0c01b3..4fcf05a2 100644 --- a/datacenterlight/templatetags/custom_tags.py +++ b/datacenterlight/templatetags/custom_tags.py @@ -160,8 +160,7 @@ def get_product_name(plan_name): product_name = "" if plan_name and plan_name.startswith("generic-"): first_index_hyphen = plan_name.index("-") + 1 - product_id = plan_name[first_index_hyphen: - (plan_name[first_index_hyphen:].index("-")) + first_index_hyphen] + product_id = plan_name[first_index_hyphen:(plan_name[first_index_hyphen:].index("-")) + first_index_hyphen] try: product = GenericProduct.objects.get(id=product_id) product_name = product.product_name From fdb790bac72473a39a33c4755a413d557169e3d8 Mon Sep 17 00:00:00 2001 From: PCoder Date: Fri, 16 Feb 2024 16:24:37 +0530 Subject: [PATCH 28/60] Use the actual plan name instead of the generic plan id --- datacenterlight/views.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/datacenterlight/views.py b/datacenterlight/views.py index 5c333a63..941f6fae 100644 --- a/datacenterlight/views.py +++ b/datacenterlight/views.py @@ -42,6 +42,8 @@ from .utils import ( get_cms_integration, create_vm, clear_all_session_vars, validate_vat_number ) +from datacenterlight.templatetags.custom_tags import get_product_name + logger = logging.getLogger(__name__) @@ -900,15 +902,21 @@ class OrderConfirmationView(DetailView, FormView): 2 ) ) - plan_name = "generic-{0}-{1:.2f}".format( + stripe_plan_id = "generic-{0}-{1:.2f}".format( request.session['generic_payment_details']['product_id'], amount_to_be_charged ) - stripe_plan_id = plan_name + try: + product = GenericProduct.objects.get(id=request.session['generic_payment_details']['product_id']) + plan_name = product.product_name + except Exception as ex: + logger.debug("Error {}" % str(ex)) + plan_name = get_product_name(stripe_plan_id) recurring_interval = request.session['generic_payment_details']['recurring_interval'] if recurring_interval == "year": - plan_name = "{}-yearly".format(plan_name) - stripe_plan_id = plan_name + stripe_plan_id = "{}-yearly".format(stripe_plan_id) + plan_name = "{} (yearly)".format(plan_name) + logger.debug("Plan name = {}, Stripe Plan id = {}".format(plan_name, stripe_plan_id)) else: template = request.session.get('template') specs = request.session.get('specs') From 169dc6b1ee536fea1475828f753260d4dc6eb439 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 17 Feb 2024 18:27:44 +0900 Subject: [PATCH 29/60] Add initial script for image building --- build-image.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100755 build-image.sh diff --git a/build-image.sh b/build-image.sh new file mode 100755 index 00000000..acfb789a --- /dev/null +++ b/build-image.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +if [ $# -lt 1 ]; then + echo "$0 imageversion [push]" + echo "If push is specified, also push to our harbor" + exit 1 +fi + +tagprefix=harbor.k8s.ungleich.ch/ungleich-public/dynamicweb +version=$1; shift + +tag=${tagprefix}:${version} + +docker build -t "${tag}" . From bd4d81c286d833d97a15750d3145c53344133eb0 Mon Sep 17 00:00:00 2001 From: "app@dynamicweb-production" Date: Sat, 17 Feb 2024 11:20:12 +0100 Subject: [PATCH 30/60] Show virtual machine plan page for admin --- hosting/views.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hosting/views.py b/hosting/views.py index 3ac8c023..ce59b0d9 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -1544,7 +1544,12 @@ class VirtualMachinesPlanListView(LoginRequiredMixin, ListView): ordering = '-id' def get_queryset(self): - owner = self.request.user + username = self.request.GET.get('username') + if self.request.user.is_admin and username: + user = CustomUser.objects.get(username=username) + else: + user = self.request.user + owner = user manager = OpenNebulaManager(email=owner.username, password=owner.password) try: From 4eb470df1632ff055eac6b2a5f1f02b4df618d2e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 17 Feb 2024 20:48:17 +0900 Subject: [PATCH 31/60] [docker] switch to python 3.5 --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 50b81cbb..d12c54ff 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,5 @@ -FROM python:3.10.0-alpine3.15 +# FROM python:3.10.0-alpine3.15 +FROM python:3.5-alpine3.12 WORKDIR /usr/src/app From 0d7f10776c3c0ec0b4b1aaa82a07bddf45169071 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 17 Feb 2024 20:49:31 +0900 Subject: [PATCH 32/60] [docker] push if build is ok --- build-image.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build-image.sh b/build-image.sh index acfb789a..0ac898ed 100755 --- a/build-image.sh +++ b/build-image.sh @@ -2,6 +2,7 @@ if [ $# -lt 1 ]; then echo "$0 imageversion [push]" + echo "Version could be: $(git describe --always)" echo "If push is specified, also push to our harbor" exit 1 fi @@ -11,4 +12,7 @@ version=$1; shift tag=${tagprefix}:${version} +set -ex + docker build -t "${tag}" . +docker push "${tag}" From f178be8395a95e5023756e2824efbadac2b44216 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 19 Feb 2024 20:42:34 +0530 Subject: [PATCH 33/60] Update .dockerignore: ignore .env --- .dockerignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.dockerignore b/.dockerignore index 6b8710a7..a715c9d7 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1,2 @@ .git +.env From 893c8168469382426d59b93606baf2e1e6dc4520 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 19 Feb 2024 20:43:33 +0530 Subject: [PATCH 34/60] Add apks required for the build on alpine 3.12 --- Dockerfile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d12c54ff..bee11218 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,12 @@ RUN apk add --update --no-cache \ build-base \ openldap-dev \ python3-dev \ - libpq-dev \ + postgresql-dev \ + jpeg-dev \ + libxml2-dev \ + libxslt-dev \ + libmemcached-dev \ + zlib-dev \ && rm -rf /var/cache/apk/* # FIX https://github.com/python-ldap/python-ldap/issues/432 From b6ff2b62c1da90a8a4c5bfebe10f6edb573d57fa Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 19 Feb 2024 20:44:17 +0530 Subject: [PATCH 35/60] Add comment for alpine 3.14 requirement --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index bee11218..7b5440af 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,6 +16,8 @@ RUN apk add --update --no-cache \ zlib-dev \ && rm -rf /var/cache/apk/* +## For alpine 3.15 replace postgresql-dev with libpq-dev + # FIX https://github.com/python-ldap/python-ldap/issues/432 RUN echo 'INPUT ( libldap.so )' > /usr/lib/libldap_r.so From 8d13629c8b775c63cc8dd8fda7412c36fd09aefa Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 19 Feb 2024 20:49:29 +0530 Subject: [PATCH 36/60] Use proper library path for Pillow --- Dockerfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 7b5440af..395ebcc9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,5 +22,8 @@ RUN apk add --update --no-cache \ RUN echo 'INPUT ( libldap.so )' > /usr/lib/libldap_r.so COPY requirements.txt ./ -RUN pip install --no-cache-dir -r requirements.txt + +# Pillow seems to need LIBRARY_PATH set as follows: (see: https://github.com/python-pillow/Pillow/issues/1763#issuecomment-222383534) +RUN LIBRARY_PATH=/lib:/usr/lib /bin/sh -c "pip install --no-cache-dir -r requirements.txt" + COPY ./ . From 9e98125b13e400d0c083589b252527872fa58a56 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 19 Feb 2024 20:50:10 +0530 Subject: [PATCH 37/60] Use the same django-filer version being used on production --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8d04a189..73cdf987 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,7 +25,7 @@ django-compressor==2.0 django-debug-toolbar==1.4 python-dotenv==0.10.3 django-extensions==1.6.7 -django-filer==2.1.2 +django-filer==1.2.0 django-filter==0.13.0 django-formtools==1.0 django-guardian==1.4.4 From 26f3a1881decdcc98c0ae9add4a627af0833a4b7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 20 Feb 2024 16:25:13 +0900 Subject: [PATCH 38/60] make build image only push if push is specified --- build-image.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/build-image.sh b/build-image.sh index 0ac898ed..64a67fd6 100755 --- a/build-image.sh +++ b/build-image.sh @@ -15,4 +15,9 @@ tag=${tagprefix}:${version} set -ex docker build -t "${tag}" . -docker push "${tag}" + +push=$1; shift + +if [ "$push" ]; then + docker push "${tag}" +fi From 8b06c2c6e9b599ce887f8e26f451878511ba3557 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 20 Feb 2024 17:18:29 +0900 Subject: [PATCH 39/60] docker: add entrypoint and add support for dynamic config --- Dockerfile | 3 +++ dynamicweb/settings/base.py | 6 ++++++ entrypoint.sh | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 entrypoint.sh diff --git a/Dockerfile b/Dockerfile index 395ebcc9..4c1a9a66 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,3 +27,6 @@ COPY requirements.txt ./ RUN LIBRARY_PATH=/lib:/usr/lib /bin/sh -c "pip install --no-cache-dir -r requirements.txt" COPY ./ . +COPY entrypoint.sh / + +ENTRYPOINT ["/entrypoint.sh" ] diff --git a/dynamicweb/settings/base.py b/dynamicweb/settings/base.py index f03042dc..b7705e17 100644 --- a/dynamicweb/settings/base.py +++ b/dynamicweb/settings/base.py @@ -777,3 +777,9 @@ if DEBUG: from .local import * # flake8: noqa else: from .prod import * # flake8: noqa + +# Try to load dynamic configuration, if it exists +try: + from .dynamic import * # flake8: noqa +except ImportError: + pass diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 00000000..e207a457 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +set -uex + +cd /usr/src/app/ +cat > dynamicweb/settings/dynamic.py < Date: Tue, 20 Feb 2024 17:19:05 +0900 Subject: [PATCH 40/60] entrypoint: make executable --- entrypoint.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 entrypoint.sh diff --git a/entrypoint.sh b/entrypoint.sh old mode 100644 new mode 100755 From c4f6780a0e0c4ac91b6636e2725dc0b581a6c361 Mon Sep 17 00:00:00 2001 From: PCoder Date: Fri, 22 Mar 2024 16:54:54 +0530 Subject: [PATCH 41/60] Add management command fix_generic_stripe_plan_product_names.py --- .../fix_generic_stripe_plan_product_names.py | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 datacenterlight/management/commands/fix_generic_stripe_plan_product_names.py diff --git a/datacenterlight/management/commands/fix_generic_stripe_plan_product_names.py b/datacenterlight/management/commands/fix_generic_stripe_plan_product_names.py new file mode 100644 index 00000000..2773009d --- /dev/null +++ b/datacenterlight/management/commands/fix_generic_stripe_plan_product_names.py @@ -0,0 +1,54 @@ +from django.core.management.base import BaseCommand +from datacenterlight.tasks import handle_metadata_and_emails +from datacenterlight.models import StripePlan +from opennebula_api.models import OpenNebulaManager +from membership.models import CustomUser +from hosting.models import GenericProduct +import logging +import json +import sys +import stripe + +logger = logging.getLogger(__name__) + + +class Command(BaseCommand): + help = '''Stripe plans created before version 3.4 saved the plan name like generic-{subscription_id}-amount. This + command aims at replacing this with the actual product name + ''' + + def handle(self, *args, **options): + cnt = 0 + self.stdout.write( + self.style.SUCCESS( + 'In Fix generic stripe plan product names' + ) + ) + plans_to_change = StripePlan.objects.filter(stripe_plan_id__startswith='generic') + for plan in plans_to_change: + response = input("Press 'y' to continue: ") + + # Check if the user entered 'y' + if response.lower() == 'y': + plan_name = plan.stripe_plan_id + first_index_hyphen = plan_name.index("-") + 1 + product_id = plan_name[ + first_index_hyphen:(plan_name[first_index_hyphen:].index("-")) + first_index_hyphen] + gp = GenericProduct.objects.get(id=product_id) + if gp: + cnt += 1 + # update stripe + sp = stripe.Plan.retrieve(plan_name) + pr = stripe.Product.retrieve(sp.product) + pr.name = gp.product_name + pr.save() + # update local + spl = StripePlan.objects.get(stripe_plan_id=plan_name) + spl.stripe_plan_name = gp.product_name + spl.save() + print("%s. %s => %s" % (cnt, plan_name, gp.product_name)) + else: + print("Invalid input. Please try again.") + sys.exit() + + print("Done") \ No newline at end of file From 92cfe71bbe0012b4fcab5a37c26b1f000e60641e Mon Sep 17 00:00:00 2001 From: "app@dynamicweb-production" Date: Wed, 8 May 2024 09:57:56 +0200 Subject: [PATCH 42/60] Fix invoices list not showing one time charges --- hosting/templates/hosting/invoices.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosting/templates/hosting/invoices.html b/hosting/templates/hosting/invoices.html index 69ed4577..347b1ff4 100644 --- a/hosting/templates/hosting/invoices.html +++ b/hosting/templates/hosting/invoices.html @@ -87,7 +87,7 @@ {% for ho, stripe_charge_data in invs_charge %} - {{ ho | get_line_item_from_hosting_order_charge }} + {{ ho.id | get_line_item_from_hosting_order_charge }} {% endfor %} From 4f8bd3b45fda38ef5391ddb6a37424f02259ffa5 Mon Sep 17 00:00:00 2001 From: "app@dynamicweb-production" Date: Thu, 20 Jun 2024 13:58:19 +0200 Subject: [PATCH 43/60] Fix stripe_chgs object; make it consistent --- hosting/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosting/views.py b/hosting/views.py index ce59b0d9..637a112b 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -1339,7 +1339,7 @@ class InvoiceListView(LoginRequiredMixin, TemplateView): ).order_by('-created_at') stripe_chgs = [] for ho in hosting_orders: - stripe_chgs.append({ho.id: stripe.Charge.retrieve(ho.stripe_charge_id)}) + stripe_chgs.append({ho: stripe.Charge.retrieve(ho.stripe_charge_id)}) paginator_charges = Paginator(stripe_chgs, 10) try: From 3736f522ddee781c086d0f2bc9f22b470fe78e4a Mon Sep 17 00:00:00 2001 From: "app@dynamicweb-production" Date: Thu, 20 Jun 2024 14:00:50 +0200 Subject: [PATCH 44/60] Debug messages --- datacenterlight/templatetags/custom_tags.py | 1 + datacenterlight/views.py | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/datacenterlight/templatetags/custom_tags.py b/datacenterlight/templatetags/custom_tags.py index 4fcf05a2..fc39eec7 100644 --- a/datacenterlight/templatetags/custom_tags.py +++ b/datacenterlight/templatetags/custom_tags.py @@ -73,6 +73,7 @@ def get_line_item_from_hosting_order_charge(hosting_order_id): :return: """ try: + print("Hositng order id = %s" % hosting_order_id) hosting_order = HostingOrder.objects.get(id = hosting_order_id) if hosting_order.stripe_charge_id: return mark_safe(""" diff --git a/datacenterlight/views.py b/datacenterlight/views.py index 941f6fae..1c770b3a 100644 --- a/datacenterlight/views.py +++ b/datacenterlight/views.py @@ -910,7 +910,7 @@ class OrderConfirmationView(DetailView, FormView): product = GenericProduct.objects.get(id=request.session['generic_payment_details']['product_id']) plan_name = product.product_name except Exception as ex: - logger.debug("Error {}" % str(ex)) + logger.debug("Errori {}" % str(ex)) plan_name = get_product_name(stripe_plan_id) recurring_interval = request.session['generic_payment_details']['recurring_interval'] if recurring_interval == "year": @@ -1009,6 +1009,8 @@ class OrderConfirmationView(DetailView, FormView): # due to some reason. So, we would want to dissociate this card # here. # ... + logger.debug("In 1 ***") + logger.debug("stripe_subscription_obj == %s" % stripe_subscription_obj) msg = subscription_result.get('error') return show_error(msg, self.request) elif stripe_subscription_obj.status == 'incomplete': @@ -1222,6 +1224,7 @@ def set_user_card(card_id, stripe_api_cus_id, custom_user, stripe_customer=custom_user.stripecustomer, card_details=card_details_response ) + logger.debug("ucd = %s" % ucd) UserCardDetail.save_default_card_local( custom_user.stripecustomer.stripe_id, ucd.card_id @@ -1231,6 +1234,7 @@ def set_user_card(card_id, stripe_api_cus_id, custom_user, 'brand': ucd.brand, 'card_id': ucd.card_id } + logger.debug("card_detail_dict = %s" % card_details_dict) return card_details_dict @@ -1435,6 +1439,7 @@ def do_provisioning(request, stripe_api_cus_id, card_details_response, card_details_dict = set_user_card(card_id, stripe_api_cus_id, custom_user, card_details_response) + logger.debug("after set_user_card %s" % card_details_dict) # Save billing address billing_address_data.update({ @@ -1457,6 +1462,7 @@ def do_provisioning(request, stripe_api_cus_id, card_details_response, vat_number=billing_address_data['vat_number'] ) billing_address.save() + logger.debug("billing_address saved") order = HostingOrder.create( price=request['generic_payment_details']['amount'], @@ -1464,6 +1470,7 @@ def do_provisioning(request, stripe_api_cus_id, card_details_response, billing_address=billing_address, vm_pricing=VMPricing.get_default_pricing() ) + logger.debug("hosting order created") # Create a Hosting Bill HostingBill.create(customer=stripe_cus, @@ -1520,7 +1527,9 @@ def do_provisioning(request, stripe_api_cus_id, card_details_response, ["%s=%s" % (k, v) for (k, v) in context.items()]), 'reply_to': [context['email']], } + logger.debug("Sending email") send_plain_email_task.delay(email_data) + logger.debug("After Sending email") recurring_text = _(" This is a monthly recurring plan.") if gp_details['recurring_interval'] == "year": recurring_text = _(" This is an yearly recurring plan.") @@ -1544,6 +1553,7 @@ def do_provisioning(request, stripe_api_cus_id, card_details_response, ), 'reply_to': ['info@ungleich.ch'], } + logger.debug("Before Sending customer email") send_plain_email_task.delay(email_data) redirect_url = reverse('datacenterlight:index') logger.debug("Sent user/admin emails") From 94a9ac31473d470840f08bc837c2ed086bfbe636 Mon Sep 17 00:00:00 2001 From: "app@dynamicweb-production" Date: Thu, 26 Sep 2024 11:13:56 +0200 Subject: [PATCH 45/60] Add change_fi_vatrate_2024.py management command --- .../commands/change_fi_vatrate_2024.py | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 hosting/management/commands/change_fi_vatrate_2024.py diff --git a/hosting/management/commands/change_fi_vatrate_2024.py b/hosting/management/commands/change_fi_vatrate_2024.py new file mode 100644 index 00000000..6947b6eb --- /dev/null +++ b/hosting/management/commands/change_fi_vatrate_2024.py @@ -0,0 +1,143 @@ +from django.core.management.base import BaseCommand +import datetime +import csv +import logging +import stripe +from hosting.models import VATRates, StripeTaxRate +from utils.hosting_utils import get_vat_rate_for_country +from django.conf import settings +from membership.models import CustomUser, StripeCustomer + +stripe.api_key = settings.STRIPE_API_PRIVATE_KEY + +logger = logging.getLogger(__name__) + +class Command(BaseCommand): + help = '''FI vat rate changes on 2024-09-01 from 24% to 25.5%. This commands makes the necessary changes''' + + def handle(self, *args, **options): + MAKE_MODIFS=False + try: + country_to_change = 'FI' + currency_to_change = 'EUR' + new_rate = 25.5 + user_country_vat_rate = get_vat_rate_for_country(country_to_change) + logger.debug("Existing VATRate for %s %s " % (country_to_change, user_country_vat_rate)) + vat_rate = VATRates.objects.get( + territory_codes=country_to_change, start_date__isnull=False, stop_date=None + ) + logger.debug("VAT rate for %s is %s" % (country_to_change, vat_rate.rate)) + logger.debug("vat_rate object = %s" % vat_rate) + logger.debug("Create end date for the VATRate %s" % vat_rate.id) + #if MAKE_MODIFS: + # vat_rate.stop_date = datetime.date(2024, 8, 31) + # vat_rate.save() + # print("Creating a new VATRate for FI") + # obj, created = VATRates.objects.get_or_create( + # start_date=datetime.date(2024, 9, 1), + # stop_date=None, + # territory_codes=country_to_change, + # currency_code=currency_to_change, + # rate=new_rate * 0.01, + # rate_type="standard", + # description="FINLAND standard VAT (added manually on %s)" % datetime.datetime.now() + # ) + # if created: + # logger.debug("Created new VAT Rate for %s with the new rate %s" % (country_to_change, new_rate)) + # logger.debug(obj) + # else: + # logger.debug("VAT Rate for %s already exists with the rate %s" % (country_to_change, new_rate)) + logger.debug("Getting all subscriptions of %s that need a VAT Rate change") + subscriptions = stripe.Subscription.list(limit=100) # Increase the limit to 100 per page (maximum) + fi_subs = [] + + while subscriptions: + for subscription in subscriptions: + if len(subscription.default_tax_rates) > 0 and subscription.default_tax_rates[0].jurisdiction and subscription.default_tax_rates[0].jurisdiction.lower() == 'fi': + fi_subs.append(subscription) + elif len(subscription.default_tax_rates) > 0: + print("subscription %s belongs to %s" % (subscription.id, subscription.default_tax_rates[0].jurisdiction)) + else: + print("subscription %s does not have a tax rate" % subscription.id) + if subscriptions.has_more: + print("FETCHING MORE") + subscriptions = stripe.Subscription.list(limit=100, starting_after=subscriptions.data[-1]) + else: + break + logger.debug("There are %s FI subscription that need VAT rate update" % len(fi_subs)) + + # CSV column headers + csv_headers = [ + "customer_name", + "customer_email", + "stripe_customer_id", + "subscription_id", + "subscription_name", + "amount", + "vat_rate" + ] + # CSV file name + csv_filename = "fi_subscriptions_change_2024.csv" + # Write subscription data to CSV file + with open(csv_filename, mode='w', newline='') as csv_file: + writer = csv.DictWriter(csv_file, fieldnames=csv_headers) + writer.writeheader() + + for subscription in fi_subs: + subscription_id = subscription["id"] + stripe_customer_id = subscription.get("customer", "") + vat_rate = subscription.get("tax_percent", "") + c_user = CustomUser.objects.get( + id=StripeCustomer.objects.filter(stripe_id=stripe_customer_id)[0].user.id) + if c_user: + customer_name = c_user.name.encode('utf-8') + customer_email = c_user.email + items = subscription.get("items", {}).get("data", []) + for item in items: + subscription_name = item.get("plan", {}).get("id", "") + amount = item.get("plan", {}).get("amount", "") + + # Convert amount to a proper format (e.g., cents to dollars) + amount_in_chf = amount / 100 # Adjust this conversion as needed + + # Writing to CSV + writer.writerow({ + "customer_name": customer_name, + "customer_email": customer_email, + "stripe_customer_id": stripe_customer_id, + "subscription_id": subscription_id, + "subscription_name": subscription_name, + "amount": amount_in_chf, + "vat_rate": vat_rate # Fill in VAT rate if available + }) + else: + print("No customuser for %s %s" % (stripe_customer_id, subscription_id)) + + + if MAKE_MODIFS: + print("Making modifications now") + tax_rate_obj = stripe.TaxRate.create( + display_name="VAT", + description="VAT for %s" % country_to_change, + jurisdiction=country_to_change, + percentage=new_rate, + inclusive=False, + ) + stripe_tax_rate = StripeTaxRate.objects.create( + display_name=tax_rate_obj.display_name, + description=tax_rate_obj.description, + jurisdiction=tax_rate_obj.jurisdiction, + percentage=tax_rate_obj.percentage, + inclusive=False, + tax_rate_id=tax_rate_obj.id + ) + + for fi_sub in fi_subs: + fi_sub.default_tax_rates = [stripe_tax_rate.tax_rate_id] + fi_sub.save() + logger.debug("Default tax rate updated for %s" % fi_sub.id) + else: + print("Not making any modifications because MAKE_MODIFS=False") + + except Exception as e: + print(" *** Error occurred. Details {}".format(str(e))) From 86836f3d1eadf2988a491258a966678b7ef5e2d4 Mon Sep 17 00:00:00 2001 From: PCoder Date: Thu, 27 Mar 2025 15:39:24 +0530 Subject: [PATCH 46/60] Check those VMs that are displayed to the public --- datacenterlight/management/commands/check_vm_templates.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/datacenterlight/management/commands/check_vm_templates.py b/datacenterlight/management/commands/check_vm_templates.py index db36fde8..c550cd5d 100644 --- a/datacenterlight/management/commands/check_vm_templates.py +++ b/datacenterlight/management/commands/check_vm_templates.py @@ -1,6 +1,7 @@ from django.core.management.base import BaseCommand from opennebula_api.models import OpenNebulaManager from datacenterlight.models import VMTemplate +from datacenterlight.cms_models import DCLCalculatorPluginModel from membership.models import CustomUser from django.conf import settings @@ -31,7 +32,11 @@ class Command(BaseCommand): PROJECT_PATH = os.path.abspath(os.path.dirname(__name__)) if not os.path.exists("%s/outputs" % PROJECT_PATH): os.mkdir("%s/outputs" % PROJECT_PATH) - for vm_template in VMTemplate.objects.all(): + public_templates_plugin = DCLCalculatorPluginModel.objects.filter(cmsplugin_ptr_id=23356).first() + ipv6_templates_plugin = DCLCalculatorPluginModel.objects.filter(cmsplugin_ptr_id=21943).first() + templates = public_templates_plugin.vm_templates_to_show + ipv6_templates_plugin.vm_templates_to_show + vm_templates = VMTemplate.objects.filter(opennebula_vm_template_id__in=templates) + for vm_template in vm_templates: vm_name = 'test-%s' % vm_template.name vm_id = manager.create_vm( template_id=vm_template.opennebula_vm_template_id, From 8e9315b12de1670837722e2e5163f679381b26a8 Mon Sep 17 00:00:00 2001 From: PCoder Date: Thu, 27 Mar 2025 16:13:22 +0530 Subject: [PATCH 47/60] Fix separate messages for errors and inform admin about errors --- .../management/commands/check_vm_templates.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/datacenterlight/management/commands/check_vm_templates.py b/datacenterlight/management/commands/check_vm_templates.py index c550cd5d..365ca1f6 100644 --- a/datacenterlight/management/commands/check_vm_templates.py +++ b/datacenterlight/management/commands/check_vm_templates.py @@ -3,7 +3,7 @@ from opennebula_api.models import OpenNebulaManager from datacenterlight.models import VMTemplate from datacenterlight.cms_models import DCLCalculatorPluginModel from membership.models import CustomUser - +from utils.tasks import send_plain_email_task from django.conf import settings from time import sleep import datetime @@ -22,6 +22,7 @@ class Command(BaseCommand): def handle(self, *args, **options): result_dict = {} + error_dict = {} user_email = options['user_email'] if 'user_email' in options else "" if user_email: @@ -37,7 +38,7 @@ class Command(BaseCommand): templates = public_templates_plugin.vm_templates_to_show + ipv6_templates_plugin.vm_templates_to_show vm_templates = VMTemplate.objects.filter(opennebula_vm_template_id__in=templates) for vm_template in vm_templates: - vm_name = 'test-%s' % vm_template.name + vm_name = 'test-%s-%s' % (vm_template.vm_type, vm_template.name) vm_id = manager.create_vm( template_id=vm_template.opennebula_vm_template_id, specs=specs, @@ -57,6 +58,7 @@ class Command(BaseCommand): %s %s''' % (vm_name, vm_template.opennebula_vm_template_id, vm_template.vm_type) + error_dict[vm_name] = result_dict[vm_name] self.stdout.write(self.style.ERROR(result_dict[vm_name])) sleep(1) date_str = datetime.datetime.strftime( @@ -67,4 +69,11 @@ class Command(BaseCommand): 'w', encoding='utf-8') as f: f.write(json.dumps(result_dict)) + email_data = { + 'subject': 'Check VM Templates ERROR', + 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, + 'to': [settings.ADMIN_EMAIL], + 'body': json.dumps(error_dict), + } + send_plain_email_task.delay(email_data) self.stdout.write(self.style.SUCCESS("Done")) From ca099d8c83a5d92651a22855b88b9ca84f6b9004 Mon Sep 17 00:00:00 2001 From: PCoder Date: Thu, 27 Mar 2025 16:21:33 +0530 Subject: [PATCH 48/60] Send error message only if there is an error --- .../management/commands/check_vm_templates.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/datacenterlight/management/commands/check_vm_templates.py b/datacenterlight/management/commands/check_vm_templates.py index 365ca1f6..d30e5b0d 100644 --- a/datacenterlight/management/commands/check_vm_templates.py +++ b/datacenterlight/management/commands/check_vm_templates.py @@ -69,11 +69,12 @@ class Command(BaseCommand): 'w', encoding='utf-8') as f: f.write(json.dumps(result_dict)) - email_data = { - 'subject': 'Check VM Templates ERROR', - 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, - 'to': [settings.ADMIN_EMAIL], - 'body': json.dumps(error_dict), - } - send_plain_email_task.delay(email_data) + if error_dict: + email_data = { + 'subject': 'Check VM Templates ERROR', + 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, + 'to': [settings.ADMIN_EMAIL], + 'body': json.dumps(error_dict), + } + send_plain_email_task.delay(email_data) self.stdout.write(self.style.SUCCESS("Done")) From fc1dc37840619cf5999aa00ab9582f0c067b4aa2 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sat, 29 Mar 2025 12:55:17 +0530 Subject: [PATCH 49/60] Update .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 2d923e99..a41d813d 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,6 @@ secret-key !.gitkeep *.orig .vscode/settings.json +2024-* +2025-* +2023-* From 60ddfa78b066849630857e7595fd121a93079810 Mon Sep 17 00:00:00 2001 From: PCoder Date: Fri, 16 May 2025 16:05:50 +0530 Subject: [PATCH 50/60] Handle getting the correct user_card_detail Fixes Traceback (most recent call last): File "", line 2, in File "/home/app/pyvenv/lib/python3.5/site-packages/django/db/models/manager.py", line 122, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "/home/app/pyvenv/lib/python3.5/site-packages/django/db/models/query.py", line 391, in get (self.model._meta.object_name, num) hosting.models.MultipleObjectsReturned: get() returned more than one UserCardDetail -- it returned 2! --- datacenterlight/views.py | 6 +-- hosting/models.py | 88 +++++++++++++++++++++++++++++++++++++++- hosting/views.py | 6 +-- 3 files changed, 93 insertions(+), 7 deletions(-) diff --git a/datacenterlight/views.py b/datacenterlight/views.py index 1c770b3a..709d1c44 100644 --- a/datacenterlight/views.py +++ b/datacenterlight/views.py @@ -613,7 +613,7 @@ class OrderConfirmationView(DetailView, FormView): # TODO check when we go through this case (to me, it seems useless) card_id = self.request.session.get('card_id') logger.debug("NO id_payment_method, using card: %s" % card_id) - card_detail = UserCardDetail.objects.get(id=card_id) + card_detail = UserCardDetail.get_ucd_from_card_id(card_id=card_id) context['cc_last4'] = card_detail.last4 context['cc_brand'] = card_detail.brand context['cc_exp_year'] = card_detail.exp_year @@ -852,7 +852,7 @@ class OrderConfirmationView(DetailView, FormView): return show_error(msg, self.request) elif 'card_id' in request.session: card_id = request.session.get('card_id') - user_card_detail = UserCardDetail.objects.get(id=card_id) + user_card_detail = UserCardDetail.get_ucd_from_card_id(card_id=card_id) card_details_dict = { 'last4': user_card_detail.last4, 'brand': user_card_detail.brand, @@ -1206,7 +1206,7 @@ def set_user_card(card_id, stripe_api_cus_id, custom_user, card_details_response): if card_id: logger.debug("card_id %s was in request" % card_id) - user_card_detail = UserCardDetail.objects.get(id=card_id) + user_card_detail = UserCardDetail.get_ucd_from_card_id(card_id=card_id) card_details_dict = { 'last4': user_card_detail.last4, 'brand': user_card_detail.brand, diff --git a/hosting/models.py b/hosting/models.py index b51d8616..5cc3d0fd 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -700,7 +700,7 @@ class UserCardDetail(AssignPermissionsMixin, models.Model): @staticmethod def save_default_card_local(stripe_api_cus_id, card_id): stripe_cust = StripeCustomer.objects.get(stripe_id=stripe_api_cus_id) - user_card_detail = UserCardDetail.objects.get( + user_card_detail = UserCardDetail.get_ucd_from_stripe_cust_n_card_id( stripe_customer=stripe_cust, card_id=card_id ) for card in stripe_cust.usercarddetail_set.all(): @@ -709,6 +709,92 @@ class UserCardDetail(AssignPermissionsMixin, models.Model): user_card_detail.preferred = True user_card_detail.save() + @staticmethod + def get_ucd_from_card_id(card_id): + try: + user_card_details = UserCardDetail.objects.filter( + card_id=card_id + ).order_by('-id') + + if user_card_details.count() > 1: + # Log a warning about the duplicate entries + logger.warning( + f"Multiple UserCardDetail objects found for card_id={card_id}. " + f"Found {user_card_details.count()} objects. Using the latest one." + ) + # Use the first object found + user_card_detail = user_card_details.first() + elif user_card_details.count() == 1: + # Exactly one object found, proceed as intended + user_card_detail = user_card_details.first() + else: + # No object found for the given customer and card_id. + # Depending on expected behavior, you might want to raise an error or handle this case. + # If the original get() call happened here, it would raise DoesNotExist. + logger.error( + f"No UserCardDetail found for card_id={card_id}." + ) + raise UserCardDetail.DoesNotExist(f"No UserCardDetail found for card {card_id}") + if user_card_details.count() > 1: + # Log a warning about the duplicate entries + logger.warning( + f"Multiple UserCardDetail objects found for card_id={card_id}. " + f"Found {user_card_details.count()} objects. Using the first one." + ) + # Use the first object found + user_card_detail = user_card_details.first() + elif user_card_details.count() == 1: + # Exactly one object found, proceed as intended + user_card_detail = user_card_details.first() + else: + # No object found for the given customer and card_id. + # Depending on expected behavior, you might want to raise an error or handle this case. + # If the original get() call happened here, it would raise DoesNotExist. + logger.error( + f"No UserCardDetail found for card_id={card_id}." + ) + raise UserCardDetail.DoesNotExist(f"No UserCardDetail found for card {card_id}") + except Exception as e: + # Catch other potential exceptions during the filter/get process if necessary + logger.error(f"An unexpected error occurred while fetching UserCardDetail: {e}") + raise + return user_card_detail + + + @staticmethod + def get_ucd_from_stripe_cust_n_card_id(stripe_cust, card_id): + try: + user_card_details = UserCardDetail.objects.filter( + stripe_customer=stripe_cust, card_id=card_id + ).order_by('-id') + + if user_card_details.count() > 1: + # Log a warning about the duplicate entries + logger.warning( + f"Multiple UserCardDetail objects found for stripe_customer_id={stripe_cust.id} and card_id={card_id}. " + f"Found {user_card_details.count()} objects. Using the first one." + ) + # Use the first object found + user_card_detail = user_card_details.first() + elif user_card_details.count() == 1: + # Exactly one object found, proceed as intended + user_card_detail = user_card_details.first() + else: + # No object found for the given customer and card_id. + # Depending on expected behavior, you might want to raise an error or handle this case. + # If the original get() call happened here, it would raise DoesNotExist. + logger.error( + f"No UserCardDetail found for stripe_customer_id={stripe_cust.id} and card_id={card_id}." + ) + raise UserCardDetail.DoesNotExist(f"No UserCardDetail found for customer {stripe_cust.id}, card {card_id}") + + except Exception as e: + # Catch other potential exceptions during the filter/get process if necessary + logger.error(f"An unexpected error occurred while fetching UserCardDetail: {e}") + raise + return user_card_detail + + @staticmethod def get_user_card_details(stripe_customer, card_details): """ diff --git a/hosting/views.py b/hosting/views.py index 637a112b..c2470707 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -810,7 +810,7 @@ class PaymentVMView(LoginRequiredMixin, FormView): card_id = form.cleaned_data.get('card') customer = owner.stripecustomer try: - user_card_detail = UserCardDetail.objects.get(id=card_id) + user_card_detail = UserCardDetail.get_ucd_from_card_id(card_id=card_id) if not request.user.has_perm( 'view_usercarddetail', user_card_detail ): @@ -1014,7 +1014,7 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView, FormView): context['cc_exp_month'] = card_details_response['exp_month'] else: card_id = self.request.session.get('card_id') - card_detail = UserCardDetail.objects.get(id=card_id) + card_detail = UserCardDetail.get_ucd_from_card_id(card_id=card_id) context['cc_last4'] = card_detail.last4 context['cc_brand'] = card_detail.brand context['cc_exp_year'] = card_detail.exp_year @@ -1128,7 +1128,7 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView, FormView): return JsonResponse(response) else: card_id = request.session.get('card_id') - user_card_detail = UserCardDetail.objects.get(id=card_id) + user_card_detail = UserCardDetail.get_ucd_from_card_id(card_id=card_id) card_details_dict = { 'last4': user_card_detail.last4, 'brand': user_card_detail.brand, From b6239159b2765594534a2568406848ce7ac53c67 Mon Sep 17 00:00:00 2001 From: PCoder Date: Wed, 21 May 2025 11:17:15 +0530 Subject: [PATCH 51/60] Remove f-strings to make things compatible --- hosting/models.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/hosting/models.py b/hosting/models.py index 5cc3d0fd..f9bdc751 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -719,8 +719,10 @@ class UserCardDetail(AssignPermissionsMixin, models.Model): if user_card_details.count() > 1: # Log a warning about the duplicate entries logger.warning( - f"Multiple UserCardDetail objects found for card_id={card_id}. " - f"Found {user_card_details.count()} objects. Using the latest one." + "Multiple UserCardDetail objects found for card_id={}. " + "Found {} objects. Using the latest one.".format( + card_id, user_card_details.count() + ) ) # Use the first object found user_card_detail = user_card_details.first() @@ -732,14 +734,16 @@ class UserCardDetail(AssignPermissionsMixin, models.Model): # Depending on expected behavior, you might want to raise an error or handle this case. # If the original get() call happened here, it would raise DoesNotExist. logger.error( - f"No UserCardDetail found for card_id={card_id}." + "No UserCardDetail found for card_id={}.".format(card_id) ) - raise UserCardDetail.DoesNotExist(f"No UserCardDetail found for card {card_id}") + raise UserCardDetail.DoesNotExist("No UserCardDetail found for card {}".format(card_id)) if user_card_details.count() > 1: # Log a warning about the duplicate entries logger.warning( - f"Multiple UserCardDetail objects found for card_id={card_id}. " - f"Found {user_card_details.count()} objects. Using the first one." + "Multiple UserCardDetail objects found for card_id={}. " + "Found {} objects. Using the first one.".format( + card_id, user_card_details.count() + ) ) # Use the first object found user_card_detail = user_card_details.first() @@ -751,16 +755,15 @@ class UserCardDetail(AssignPermissionsMixin, models.Model): # Depending on expected behavior, you might want to raise an error or handle this case. # If the original get() call happened here, it would raise DoesNotExist. logger.error( - f"No UserCardDetail found for card_id={card_id}." + "No UserCardDetail found for card_id={}.".format(card_id) ) - raise UserCardDetail.DoesNotExist(f"No UserCardDetail found for card {card_id}") + raise UserCardDetail.DoesNotExist("No UserCardDetail found for card {}".format(card_id)) except Exception as e: # Catch other potential exceptions during the filter/get process if necessary - logger.error(f"An unexpected error occurred while fetching UserCardDetail: {e}") + logger.error("An unexpected error occurred while fetching UserCardDetail: {}".format(e)) raise return user_card_detail - @staticmethod def get_ucd_from_stripe_cust_n_card_id(stripe_cust, card_id): try: From 8ffa2d9c3c597fc7da02e13d3bc05c456bfd4066 Mon Sep 17 00:00:00 2001 From: PCoder Date: Wed, 21 May 2025 11:27:22 +0530 Subject: [PATCH 52/60] Replace more f-strings --- hosting/models.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/hosting/models.py b/hosting/models.py index f9bdc751..4c039fef 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -774,8 +774,10 @@ class UserCardDetail(AssignPermissionsMixin, models.Model): if user_card_details.count() > 1: # Log a warning about the duplicate entries logger.warning( - f"Multiple UserCardDetail objects found for stripe_customer_id={stripe_cust.id} and card_id={card_id}. " - f"Found {user_card_details.count()} objects. Using the first one." + "Multiple UserCardDetail objects found for stripe_customer_id={} and card_id={}. " + "Found {} objects. Using the first one.".format( + stripe_cust.id, card_id, user_card_details.count() + ) ) # Use the first object found user_card_detail = user_card_details.first() @@ -787,13 +789,19 @@ class UserCardDetail(AssignPermissionsMixin, models.Model): # Depending on expected behavior, you might want to raise an error or handle this case. # If the original get() call happened here, it would raise DoesNotExist. logger.error( - f"No UserCardDetail found for stripe_customer_id={stripe_cust.id} and card_id={card_id}." + "No UserCardDetail found for stripe_customer_id={} and card_id={}.".format( + stripe_cust.id, card_id + ) + ) + raise UserCardDetail.DoesNotExist( + "No UserCardDetail found for customer {}, card {}".format( + stripe_cust.id, card_id + ) ) - raise UserCardDetail.DoesNotExist(f"No UserCardDetail found for customer {stripe_cust.id}, card {card_id}") except Exception as e: # Catch other potential exceptions during the filter/get process if necessary - logger.error(f"An unexpected error occurred while fetching UserCardDetail: {e}") + logger.error("An unexpected error occurred while fetching UserCardDetail: {}".format(e)) raise return user_card_detail From 2ec89b615734c2ef8af68c57ab7cf320be5c21f4 Mon Sep 17 00:00:00 2001 From: PCoder Date: Wed, 21 May 2025 15:23:13 +0530 Subject: [PATCH 53/60] Print provisioning parameters --- datacenterlight/views.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/datacenterlight/views.py b/datacenterlight/views.py index 709d1c44..9a4bdd51 100644 --- a/datacenterlight/views.py +++ b/datacenterlight/views.py @@ -1428,6 +1428,30 @@ def do_provisioning(request, stripe_api_cus_id, card_details_response, """ logger.debug("do_provisioning") + + try: + params = { + 'request': request, + 'stripe_api_cus_id': stripe_api_cus_id, + 'card_details_response': card_details_response, + 'stripe_subscription_obj': stripe_subscription_obj, + 'stripe_onetime_charge': stripe_onetime_charge, + 'gp_details': gp_details, + 'specs': specs, + 'vm_template_id': vm_template_id, + 'template': template, + 'billing_address_data': billing_address_data, + 'real_request': real_request + } + print("Input Parameters:") + for key, value in params.items(): + try: + print("{}: {}".format(key, value)) + except Exception as e: + print("{}: [Error printing value: {}]".format(key, str(e))) + except Exception as e: + print("Error printing parameters: {}".format(str(e))) + user = request.get('user', None) # Create user if the user is not logged in and if he is not already From 4c0a1fd07f768318899265d0627deba321017009 Mon Sep 17 00:00:00 2001 From: PCoder Date: Tue, 27 May 2025 10:08:09 +0530 Subject: [PATCH 54/60] Debug --- datacenterlight/views.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/datacenterlight/views.py b/datacenterlight/views.py index 9a4bdd51..9ce2efd9 100644 --- a/datacenterlight/views.py +++ b/datacenterlight/views.py @@ -201,6 +201,12 @@ class IndexView(CreateView): ssd_size=storage, pricing_name=vm_pricing_name ) + if request.user.id == 51: + print("User is test") + price = 0 + vat = 0 + vat_percent = 0 + discount = 0 specs = { 'cpu': cores, 'memory': memory, @@ -588,6 +594,9 @@ class OrderConfirmationView(DetailView, FormView): context = {} # this is amount to be charge/subscribed before VAT and discount # and expressed in chf. To convert to cents, multiply by 100 + print("******************************") + print("User = {}, ID = {}".format(request.user, request.user.id)) + print("******************************") amount_to_charge = 0 vm_specs = None if (('specs' not in request.session or 'user' not in request.session) @@ -1621,7 +1630,7 @@ def do_provisioning(request, stripe_api_cus_id, card_details_response, def get_error_response_dict(msg, request): - logger.error(msg) + logger.debug("Init get_error_response_dict {}".format(msg)) response = { 'status': False, 'redirect': "{url}#{section}".format( From 4e978f62eaa2f3c90520a4f8b16a4b7ae9d37834 Mon Sep 17 00:00:00 2001 From: PCoder Date: Tue, 27 May 2025 10:47:06 +0530 Subject: [PATCH 55/60] More debug --- datacenterlight/views.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/datacenterlight/views.py b/datacenterlight/views.py index 9ce2efd9..1e486242 100644 --- a/datacenterlight/views.py +++ b/datacenterlight/views.py @@ -656,6 +656,12 @@ class OrderConfirmationView(DetailView, FormView): pricing_name=vm_specs['pricing_name'], vat_rate=user_country_vat_rate * 100 ) + if request.user.id == 51: + print("User is test") + price = 0 + vat = 0 + vat_percent = 0 + discount = {"amount": 0} vm_specs["price"] = price vm_specs["price_after_discount"] = price - discount["amount"] amount_to_charge = price From 018c3b5bba95c2c4ad435c62aa839dc39d985e90 Mon Sep 17 00:00:00 2001 From: PCoder Date: Tue, 27 May 2025 10:58:33 +0530 Subject: [PATCH 56/60] More debugging --- datacenterlight/views.py | 6 ++++-- hosting/models.py | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/datacenterlight/views.py b/datacenterlight/views.py index 1e486242..331e0fc9 100644 --- a/datacenterlight/views.py +++ b/datacenterlight/views.py @@ -1219,6 +1219,7 @@ def get_or_create_custom_user(request, stripe_api_cus_id): def set_user_card(card_id, stripe_api_cus_id, custom_user, card_details_response): + logger.debug(":: set_user_card") if card_id: logger.debug("card_id %s was in request" % card_id) user_card_detail = UserCardDetail.get_ucd_from_card_id(card_id=card_id) @@ -1233,17 +1234,18 @@ def set_user_card(card_id, stripe_api_cus_id, custom_user, stripe_source_id=user_card_detail.card_id ) else: - logger.debug("card_id was NOT in request, using " + logger.debug(" card_id was NOT in request, using " "card_details_response") ucd = UserCardDetail.get_or_create_user_card_detail( stripe_customer=custom_user.stripecustomer, card_details=card_details_response ) - logger.debug("ucd = %s" % ucd) + logger.debug(" ucd = %s" % ucd) UserCardDetail.save_default_card_local( custom_user.stripecustomer.stripe_id, ucd.card_id ) + logger.debug(" after save_default_card_local") card_details_dict = { 'last4': ucd.last4, 'brand': ucd.brand, diff --git a/hosting/models.py b/hosting/models.py index 4c039fef..f17d8a57 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -699,15 +699,19 @@ class UserCardDetail(AssignPermissionsMixin, models.Model): @staticmethod def save_default_card_local(stripe_api_cus_id, card_id): + print("save_default_card_local {}, {}".format(stripe_api_cus_id, card_id)) stripe_cust = StripeCustomer.objects.get(stripe_id=stripe_api_cus_id) + print(" stripe_cust={}".format(stripe_cust)) user_card_detail = UserCardDetail.get_ucd_from_stripe_cust_n_card_id( stripe_customer=stripe_cust, card_id=card_id ) + print(" user_card_detail={}".format(user_card_detail)) for card in stripe_cust.usercarddetail_set.all(): card.preferred = False card.save() user_card_detail.preferred = True user_card_detail.save() + print(" save_default_card_local DONE") @staticmethod def get_ucd_from_card_id(card_id): From f8ba89c1934285bcb109b63afb2ce1ff23301d0b Mon Sep 17 00:00:00 2001 From: PCoder Date: Tue, 27 May 2025 11:47:48 +0530 Subject: [PATCH 57/60] Fix params passing to method --- hosting/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hosting/models.py b/hosting/models.py index f17d8a57..12edba65 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -703,9 +703,9 @@ class UserCardDetail(AssignPermissionsMixin, models.Model): stripe_cust = StripeCustomer.objects.get(stripe_id=stripe_api_cus_id) print(" stripe_cust={}".format(stripe_cust)) user_card_detail = UserCardDetail.get_ucd_from_stripe_cust_n_card_id( - stripe_customer=stripe_cust, card_id=card_id + stripe_cust, card_id ) - print(" user_card_detail={}".format(user_card_detail)) + print(" user_card_detail={}".format(user_card_detail.__dict__)) for card in stripe_cust.usercarddetail_set.all(): card.preferred = False card.save() From 9cdf4593cfef31479dda480d86850e27208ea0f1 Mon Sep 17 00:00:00 2001 From: PCoder Date: Tue, 27 May 2025 12:02:15 +0530 Subject: [PATCH 58/60] Remove hardcode --- datacenterlight/views.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/datacenterlight/views.py b/datacenterlight/views.py index 331e0fc9..c708ff6a 100644 --- a/datacenterlight/views.py +++ b/datacenterlight/views.py @@ -203,10 +203,6 @@ class IndexView(CreateView): ) if request.user.id == 51: print("User is test") - price = 0 - vat = 0 - vat_percent = 0 - discount = 0 specs = { 'cpu': cores, 'memory': memory, @@ -658,10 +654,6 @@ class OrderConfirmationView(DetailView, FormView): ) if request.user.id == 51: print("User is test") - price = 0 - vat = 0 - vat_percent = 0 - discount = {"amount": 0} vm_specs["price"] = price vm_specs["price_after_discount"] = price - discount["amount"] amount_to_charge = price From cb16114aba6ea160dd0c04b0923e348f6d1dfa47 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 19 Oct 2026 20:53:32 +0530 Subject: [PATCH 59/60] Do not break the VM list when a VM's OpenNebula template was deleted The "my virtual machines" page showed "We could not load your VMs due to a backend connection error" for any user owning a VM whose template had been removed from OpenNebula. OpenNebulaManager.get_template() converted every failure, including WrongIdError for a missing template, into ConnectionRefusedError, and VirtualMachineSerializer.get_configuration() let that propagate, so one VM with a stale template id took down the whole list. The only log output was an empty ERROR line, because WrongIdError has no message. * Add opennebula_api.exceptions.TemplateNotFoundError and raise it from get_template() for a missing template; keep ConnectionRefusedError for genuine backend failures and log them with a traceback. * Add OpenNebulaManager.get_template_names() and resolve_template_id() so the serializer fetches the template pool once per list instead of constructing an OpenNebulaManager and fetching the pool for every VM. * get_configuration() now falls back to the template name embedded in the VM name ("