diff --git a/Cargo.lock b/Cargo.lock index 112e2dd..ca03e43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1307,6 +1307,7 @@ dependencies = [ "actix-web", "argon2", "askama", + "base64", "chrono", "futures", "futures-util", diff --git a/Cargo.toml b/Cargo.toml index 2f22475..a0cfc79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,3 +29,4 @@ tracing-actix-web = { version = "*" } tracing-subscriber = { version = "*" } uuid = { version = "*", features = ["serde"] } validator = { version = "0.14", features = ["derive"] } +base64 = "0.13.0" diff --git a/assets/css/app.css b/assets/css/app.css index e51c50c..b2b31ab 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -98,14 +98,18 @@ p { } ul, ol { - font-size: 1.3em; - margin: 0 0 1.3em 2em; + font-size: 1.1rem; + margin: 0 0 1.1rem 1.2em; } li { margin-bottom: .4em; } +terms-and-conditions li { + list-style: decimal; +} + blockquote { padding-left: 1em; border-left: 3px solid #999; diff --git a/assets/templates/base.html b/assets/templates/base.html index 73603df..6dc3c74 100644 --- a/assets/templates/base.html +++ b/assets/templates/base.html @@ -62,7 +62,7 @@ {% if h.is_above_user(account) %} - + @@ -71,17 +71,22 @@ {% endif %} + + + + + + + {% if h.is_admin(account) %} - - - - + + + +
Admin
@@ -97,7 +102,8 @@
Aktualności
- + diff --git a/assets/templates/businesses/index.html b/assets/templates/businesses/index.html index 5b210e1..912edaa 100644 --- a/assets/templates/businesses/index.html +++ b/assets/templates/businesses/index.html @@ -26,8 +26,8 @@ {% endfor %} diff --git a/assets/templates/marketplace/index.html b/assets/templates/marketplace/index.html index 7e6b21c..82e15e7 100644 --- a/assets/templates/marketplace/index.html +++ b/assets/templates/marketplace/index.html @@ -1,3 +1,12 @@ {% extends "../base.html" %} {% block content %} + + {% for offer in offers %} + + {% endfor %} + {% endblock %} diff --git a/assets/templates/offers/index.html b/assets/templates/offers/index.html new file mode 100644 index 0000000..838300d --- /dev/null +++ b/assets/templates/offers/index.html @@ -0,0 +1,13 @@ +{% extends "../base.html" %} +{% block content %} + + + {% for offer in offers %} + + {% endfor %} + +{% endblock %} diff --git a/assets/templates/terms-and-condition.html b/assets/templates/terms-and-condition.html new file mode 100644 index 0000000..0a41d36 --- /dev/null +++ b/assets/templates/terms-and-condition.html @@ -0,0 +1,708 @@ +{% extends "base.html" %} +{% block content %} + +

REGULAMIN SERIWSU INTERNETOWEGO

+ +
+

REGULAMIN SERIWSU INTERNETOWEGO
oswilno.pl

+

 

+

§ 1. DEFINICJE

+
    +
  1. + Darmowy dostęp – dostęp do funkcjonalności Serwisu określonych przez Usługodawcę, za które nie są + wymagane opłaty. +
  2. +
  3. + Osiedle - dzielnica Elsnerów w Warszawie. +
  4. +
  5. + Mieszkaniec - osoba zamieszkująca dzielnicę Elsnerów w Warszawie. +
  6. +
  7. + Upoważniony użytkownik - osoba zarejestrowana i nie będąca Mieszkańcem. +
  8. +
  9. + Gość - osoba niezarejestrowana korzystająca z serwisu. +
  10. +
  11. + Formularz – formularz służący do rejestracji Usługobiorcy oraz zawarcia Umowy z Usługodawcą dostępny na + stronie internetowej oswilno.pl. +
  12. +
  13. + Informacje organizacyjne – szczegóły dotyczące danej Usługi dostępne na stronie internetowej + oswilno.pl, jak na przykład – jeśli dotyczy - data, miejsce, szczegóły techniczne potrzebne do + wykonania Usługi, sposób płatności, osoba kontaktowa, spółka EY będąca organizatorem etc. +
  14. +
  15. + Kodeks etyki – Zasady Etyki Doradców Podatkowych, Zasady etyki zawodowej biegłych rewidentów, Kodeks + Etyki Adwokackiej oraz Kodeks Etyki Radcy Prawnego. +
  16. +
  17. + Konto - konto Usługobiorcy tworzone w procesie rejestracji w Serwisie, tworzone na potrzeby realizacji + wybranych Usług. +
  18. +
  19. + Regulamin - niniejszy regulamin Serwisu. +
  20. +
  21. + Serwis - Serwis internetowy Usługodawcy działający pod adresem oswilno.pl. +
  22. +
  23. + Usługa – dostęp do Serwisu i funkcjonalności Serwisu, w tym w szczególności, ale nie wyłącznie dostęp + do: +
      +
    • zarządzanie ogłoszeniami usług dodanych przez Mieszkańcę lub Upoważnionego użytkownika
    • +
    • zarządzanie ogłoszeniami sprzedaży przez osoby prywatne zamieszkujące Osiedle
    • +
    • zarządzanie prywatnym Kontem
    • +
    +
  24. +
  25. + Usługobiorca – Mieszkaniec, Gość lub Upoważniony użytkownik +
  26. +
  27. + Użytkownik – Mieszkaniec lub Osoba upoważniona wskazany w Formularzu, która z ramienia Usługobiorcy ma + prawo do korzystania z Serwisu. +
  28. +
+

§ 2. POSTANOWIENIA OGÓLNE

+
    +
  1. + Serwis prowadzony jest przez Usługodawcę. Adres e-mail Usługodawcy to: + adrian.wozniak@ita-prog.pl. +
  2. +
  3. + Serwis działa na zasadach określonych w niniejszym Regulaminie oraz przepisach obowiązującego prawa. +
  4. +
  5. + Serwis ma na celu prezentację oferowanych usług przez Mieszkańców. +
  6. +
  7. + Regulamin określa zakres i rodzaj Usług świadczonych drogą elektroniczną (bezpłatnych i odpłatnych) + przez Usługodawcę w ramach Serwisu, zasady świadczenia tych usług, a także tryb postępowania + reklamacyjnego. +
  8. +
  9. + Z oferowanych przez Usługodawcę Usług mogą korzystać wyłącznie Usługobiorcy. Usługodawca nie wyraża + zgody na korzystanie z Usług przez konsumentów. Konsumenci korzystają z Usług na własne ryzyko i + odpowiedzialność. +
  10. +
  11. + Usługobiorcy wyrażający chęć skorzystania z Serwisu oraz z oferowanych przez Usługodawcę Usług w + Serwisie zobowiązani są do stosowania postanowień niniejszego Regulaminu. +
  12. +
+

§ 3. WARUNKI ŚWIADCZONYCH USŁUG

+
    +
  1. 1. Za pośrednictwem Serwisu Usługodawca umożliwia: +
      +
    1. rejestrację Usługobiorcy w Serwisie,
    2. +
    3. korzystanie przez Usługobiorcę i Użytkownika z Serwisu.
    4. +
    +
  2. +
  3. + Warunkiem korzystania z Usług przez Usługobiorcę z Usługodawcą jest zapoznanie się z niniejszym + Regulaminem oraz jego akceptacja bez zmian i zastrzeżeń. +
  4. +
  5. + W Serwisie mogą być udostępniane przez Usługodawcę treści marketingowe zarówno Usługodawcy jak i innych + podmiotów w formach dozwolonych przez przepisy prawa. +
  6. +
  7. + Usługodawca określa następujące wymagania techniczne w celu korzystania z Serwisu: +
      +
    1. Komputer z dostępem do Internetu.
    2. +
    3. Dostęp do e-mail.
    4. +
    5. Przeglądarka internetowa.
    6. +
    7. Włączenie w przeglądarce internetowej Cookies oraz Javascript.
    8. +
    +
  8. +
  9. + Usługobiorca świadomy jest, że sieć Internet ma publiczny charakter i korzystanie z usług świadczonych + drogą elektroniczną może się wiązać z zagrożeniem pozyskania i modyfikowana danych Usługobiorców przez + osoby nieuprawnione, dlatego Usługobiorcy powinni stosować należyte środki techniczne, które + zminimalizują te zagrożenia. W szczególności zasadne jest stosowanie przez Usługobiorców programów + antywirusowych. +
  10. +
  11. + Usługodawca dokłada starań aby Serwis był należycie zabezpieczony. +
  12. +
  13. + Usługobiorca rozumie, że treści zamieszczone przez Usługodawcę w Serwisie mają charakter ogólny + (informacyjny), nie mają charakteru indywidualnego i nie mogą być one uważane za świadczenie usług + jakiegokolwiek doradztwa. W związku z tym rekomendacje znajdujące się w Serwisie mają charakter + wyłącznie orientacyjny, a zawarte w nich informacje nie powinny zastąpić szczegółowej analizy problemu + lub profesjonalnego osądu. Usługodawca nie ponosi odpowiedzialności za jakiekolwiek straty + powstałe w wyniku czynności podjętych lub zaniechanych na podstawie udzielonych rekomendacji. + Usługodawca zaleca, by wszelkie kwestie związane z korzystaniem z Serwisu były konsultowane z właściwym + doradcą. +
  14. +
  15. + Usługodawca zastrzega sobie prawo do nieudzielania świadczeń w ramach Usługi w stosunku do podmiotów + konkurencyjnych wobec Usługodawcy, a także wobec konsumentów niebędących Usługobiorcami. +
  16. +
+

§ 4. REJESTRACJA

+
    +
  1. + Dostęp i korzystanie z Serwisu przez Usługobiorcę jest bezpłatny. +
  2. +
  3. + Dostęp i korzystanie z Serwisu Usługobiorca otrzymuje na czas nieokreślony. +
  4. +
  5. Rejestracja odbywa się w następujący sposób: +
      +
    1. Usługobiorca akceptuje niniejszy Regulamin.
    2. +
    3. Usługobiorca podaje w Formularzu rejestracyjnym dane niezbędne do korzystania z Serwisu.
    4. +
    +
  6. +
  7. Usługobiorca powinien wypełnić Formularz rejestracyjny w następujący sposób: +
      +
    1. + wszystkie wymagane pola Formularza powinny być uzupełnione, +
    2. +
    3. + informacje wpisane do Formularza powinny dotyczyć Usługobiorcy lub osób działających w imieniu + Usługobiorcy oraz być zgodne z prawdą. +
    4. +
    5. + Usługobiorca lub osoba działająca w imieniu Usługobiorcy powinna wyrazić zgodę na przetwarzanie + jej danych osobowych zawartych w Formularzu w celu realizacji Usługi. +
    6. +
    +
  8. +
  9. + Usługodawca może kontrolować i weryfikować prawidłowości danych identyfikacyjnych Usługobiorcy i + Użytkownika, zawartych w Formularzu, co nie oznacza, że jest do tego zobowiązany. +
  10. +
  11. + Informacje i Usługi zamieszczone w Serwisie nie stanowią oferty w rozumieniu art. 66¹ KC. Usługobiorca + rejestrując się w Serwisie oraz wybierając opcję dostępu do Serwisu, składa ofertę Usługodawcy na + warunkach określonych Serwisie i Regulaminie. +
  12. +
+

§ 5. KONTO

+
    +
  1. + Użytkownikiem Konta jest osoba wskazana w Formularzu. +
  2. +
  3. + Z Konta może korzystać wyłącznie osoba wskazana w Formularzu. +
  4. +
  5. + Użytkownik jest odpowiedzialny za wszelkie działania związane z posługiwaniem się hasłem i loginem do + Konta. Użytkownik jest zobowiązany do utrzymania w ścisłej tajemnicy hasła i loginu koniecznego do + zalogowania się na Konto. Zakazane jest udostępnianie komukolwiek hasła i loginu do Konta. Hasło i login + stanowią informację poufną, do wyłącznej wiadomości Użytkownika. Użytkownik odpowiedzialny jest za dobór + hasła, zapewniającego możliwie najwyższy poziom zabezpieczenia przed jego odtworzeniem przez inne osoby + lub programy komputerowe. Wskazane jest dokonywanie zmian hasła co pewien czas (np. co 30 dni). +
  6. +
  7. + Użytkownik wskazując nazwę Użytkownika nie może podszywać się pod innych Użytkowników, Usługobiorców lub + pod Usługodawcę. +
  8. +
  9. + Użytkownik Konta w imieniu Usługobiorcy ma prawo składać oświadczenia i zaciągać zobowiązania w ramach + Serwisu prowadzonego przez Usługodawcę. +
  10. +
  11. + Powiadomienia dotyczące korzystania z Konta oraz Serwisu będą przesyłane na adres e-mail podany przez + Usługodawcę w Formularzu, przy czym Usługobiorca i/lub Użytkownik Konta może dokonać zmiany adresu + usuwając i wprowadzając odpowiednie dane w formularzu Konta. Należy weryfikować, czy podawany + Usługodawcy adres e-mail jest aktualny i poprawny. +
  12. +
  13. + Usługodawca ma prawo zablokować Użytkownikowi Konto, gdy: +
      +
    1. + Użytkownik wykorzystuje Konto z naruszeniem obowiązującego prawa oraz postanowień niniejszego + Regulaminu, +
    2. +
    3. + nazwa Konta narusza prawo, prawem chronione dobra osób trzecich, jest niezgodna z dobrymi + obyczajami, w tym jest wyrażeniem powszechnie uznanym za obraźliwe lub nazwa Konta sugeruje, że + jest to Konto wykorzystywane przez Usługodawcę, co może wprowadzać innych Usługobiorców w błąd. +
    4. +
    +
  14. +
  15. + O zamiarze zablokowania Konta Usługodawca powiadomi Usługobiorcę i/lub Użytkownika Konta z 2-dniowym + wyprzedzeniem, wzywając go do zaniechania lub usunięcia naruszeń lub ich skutków w terminie 2 dni od + otrzymania wezwania, a po bezskutecznym upływie tego terminu, zablokuje Konto. Usługodawca ma prawo + zablokować Konto w trybie natychmiastowym bez uprzedniego informowania Usługobiorcy i/lub Użytkownika + Konta, jeżeli Użytkownik Konta naruszył bezwzględnie obowiązujące przepisy prawa i oczywiste jest, że + nie jest możliwe usunięcie naruszeń lub ich skutków. +
  16. +
+

§ 6. KORZYSTANIE Z SERWISU

+
    +
  1. + Dostęp Usługobiorcy do funkcjonalności Serwisu jest bezpłatny, jednakże niektóre funkcjonalności Serwisu + wskazane przez Usługodawcę mogą być odpłatne. Usługodawca w każdym czasie może zdecydować o odpłatności + lub bezpłatności każdej funkcjonalności Serwisu. +
  2. +
  3. + Aby uzyskać dostęp do Usług znajdujących się na Serwisie, Usługobiorca musi wypełnić Formularz oraz + zaakceptować niniejszy Regulamin. +
  4. +
+

§ 7. KORZYSTANIE Z ZARZĄDZANIA OGŁOSZENIAMI USŁUG;

+
    +
  1. + Tworzenie, modyfikowanie i usuwanie usługi odbywa się przez utworzenie konta przedsiębiorcy oraz + wypełnienie formularza usługi. +
  2. +
  3. +
      +
    1. + Konto przedsiębiorcy może zostać utworzone jedynie przez Mieszkańca i/lub Upoważnionego + użytkownika. +
    2. +
    3. + Utworzenie konta Upoważnionego użytkownika jest możliwe jedynie poprzez wysłanie wiadomości + e-mail na adres adrian.wozniak@ita-prog.pl z + tytułem "Proszę o konto upoważnione" oraz opisaniem + konta w treści wiadomości. +
    4. +
    +
  4. +
  5. + Usługodawca zastrzega sobie prawo do odmowy publikowania usługi bez podania przyczyny. +
  6. +
  7. + Usługodawca nie ponosi odpowiedzialności za zmiany w ogłoszeniach opublikowanych przez właściciela + ogłoszenia. +
  8. +
  9. + Wymagane jest posiadanie przez Usługobiorcę łącza dostępowego do Internetu o szybkość transmisji minimum + 1024/256 kb/s. +
  10. +
  11. + Sprzęt komputerowy Usługobiorcy musi być wyposażony w dowolną przeglądarkę internetową. +
  12. +
  13. + Usługodawca nie ponosi odpowiedzialności za nieodpowiednią konfigurację sprzętu komputerowego + Usługobiorcy. +
  14. +
+

§ 8. KORZYSTANIE Z Targu

+
    +
  1. + Usługodawca na łamach Serwisu daje możliwość Usługobiorcom do korzystania z wystawiania prywatnych + przedmiotów na sprzedaż oraz ich przeglądania. +
  2. +
  3. + Dodawanie ogłoszenia sprzedaży w Targu jest dostępne tylko i wyłącznie dla Mieszkańców. +
  4. +
  5. + Usługodawca nie ponosi odpowiedzialności za treść danych i informacji wchodzących w skład Targu. +
  6. +
  7. + Usługodawca wskazuje, że dane i informacje zawarte w raportach, prezentacjach oraz innych dokumentach + mają charakter informacyjny i nie stanowią wiążącej prawnie potwierdzonej informacji. +
  8. +
  9. Usługodawca zaleca, aby wszelkie informacje i dane zawarte raportach, prezentacjach oraz innych + dokumentach były konsultowane z właściwym doradcą. +
  10. +
  11. Usługodawca nie ponosi odpowiedzialności wobec Usługobiorcy za treści zawarte w raportach, prezentacjach + oraz innych dokumentach. +
  12. +
+

§ 9. PRAWA I OBOWIĄZKI USŁUGOBIORCY

+
    +
  1. + Każdy Usługobiorca ma obowiązek korzystać z Serwisu w sposób zgodny z prawem i dobrymi obyczajami, mając + na uwadze poszanowanie dóbr osobistych i praw własności intelektualnej osób trzecich. +
  2. +
  3. + Usługobiorca zobowiązany jest do wprowadzania danych zgodnych ze stanem faktycznym i prawnym. +
  4. +
  5. + Usługobiorca zobowiązuje się do nieprzekazywania za pomocą Serwisu żadnych bezprawnych treści. +
  6. +
  7. + Usługobiorca ma obowiązek zapoznania się z treścią niniejszego Regulaminu. +
  8. +
  9. + Usługobiorca ma świadomość jakiej tematyki jest Serwis oraz jakiego rodzaju i zakresu Usługi są na nim + oferowane. +
  10. +
  11. + Usługobiorca jest uprawniony do korzystania z Serwisu i Usług wyłącznie na własny użytek. Nie jest + dopuszczalne wykorzystywanie zasobów i funkcji Serwisu i Usług w celu prowadzenia przez Usługobiorcę + działalności, która naruszałaby interes Usługodawcy. +
  12. +
+

§ 10. OPŁATY I METODY PŁATNOŚCI

+
    +
  1. + Wskazane przez Usługodawcę funkcjonalności Serwisu mogą być odpłatne. Wysokość opłat dostępna będzie + bezpośrednio w Serwisie. +
  2. +
  3. + Opłata wskazana w Serwisie podana jest w polskich złotych (PLN) i stanowi cenę netto, do której należy + doliczyć podatek VAT (23%). +
  4. +
  5. + Obowiązek dokonania opłaty za dostęp i korzystanie ze wskazanych funkcjonalności Serwisu jest wiążący w + chwili chęci skorzystania z tych funkcjonalności przez Usługobiorcę. +
  6. +
  7. + Usługodawca wystawi na rzecz Usługobiorcy fakturę VAT, która będzie przesyłana w formie elektronicznej w + rozumieniu przepisów Ustawy z dnia 11 marca 2004 roku o podatku od towarów i usług. Faktury + elektroniczne będą wystawiane w formacie pdf oraz doręczane Usługobiorcy na adres e-mail, na co + Usługobiorca wyraża zgodę. W przypadku chęci otrzymywania przez Usługobiorcę faktury VAT w formie + papierowej, Usługobiorca zgłosi takie zapotrzebowanie Usługodawcy na adres e-mail + adrian.wozniak@ita-prog.pl. +
  8. +
  9. + Usługobiorca dokona płatności przelewem na rachunek bankowy Usługodawcy wskazany na wystawionej fakturze + lub w treści przesłanego przez Usługodawcę emaila. +
  10. +
  11. + Usługobiorca zobowiązany jest do zapłaty za Usługę w ciągu 7 dni od momentu rejestracji, przelewem na + konto bankowe wskazane w Informacjach Organizacyjnych dotyczącej danej Usługi. Po zaksięgowaniu + płatności Usługodawca wystawi fakturę VAT i prześle ją Usługobiorcy. +
  12. +
  13. + Na wyraźną prośbę Usługobiorcy, Usługodawca może wystawić fakturę proforma. Taka prośba powinna zostać + przesłana drogą mailową do osoby kontaktowej wskazanej w Informacjach Organizacyjnych danej + Usługi. +
  14. +
+

§ 11. POSTĘPOWANIE REKLAMACYJNE

+
    +
  1. + Usługobiorca ma prawo do złożenia reklamacji wyłącznie za Usługi odpłatne, o ile do Serwisu nie ma + dostępu lub odpłatne Usługi zostały przez Usługodawcę niezrealizowane w terminie lub nienależycie + zrealizowane. +
  2. +
  3. + Reklamacje Usługobiorca winien złożyć w ciągu 14 dni od dnia, w którym Usługobiorca nie miał dostępu do + Serwisu lub od dnia, w którym odpłatna Usługa miała być wykonana na adres e-mail: ey.tax@pl.ey.com. +
  4. +
  5. + W przypadku upływu powyższego terminu prawo do złożenia reklamacji przez Usługobiorcę wygasa. +
  6. +
  7. + Usługodawca rozpatrzy reklamację Usługobiorcy niezwłocznie, jednak nie później niż w terminie 14 dni od + dnia doręczenia reklamacji. Odpowiedź Usługodawcy w sprawie reklamacji jest wysyłana na podany przez + Usługobiorcę adres e-mail. +
  8. +
  9. + W opisie reklamacji Usługobiorca ma obowiązek podać jak najwięcej informacji i okoliczności niewykonania + lub nienależycie wykonania Umowy przez Usługodawcę, w szczególności: dane Usługobiorcy w tym dane + kontaktowe i inne dane niezbędne do rozpatrzenia reklamacji. +
  10. +
+

§ 12. PRAWA I OBOWIĄZKI USŁUGODAWCY

+
    +
  1. Usługa zostanie wykonana z należytą starannością przez Usługodawcę.
  2. +
  3. Odpowiedzialność Usługodawcy jest wyłączona w przypadku gdy: +
      +
    1. + Usługobiorca i/lub Użytkownik działa bezprawnie, +
    2. +
    3. + Usługobiorca i/lub Użytkownik podał fałszywe dane i informacje o sobie oraz informacje służące + do wykonania Usługi. +
    4. +
    +
  4. +
  5. + Usługodawca ma prawo do odmowy dostępu do Serwisu i świadczenia Usług na rzecz danego Usługobiorcy na + stałe lub na czas określony przez Usługodawcę, w przypadku: +
      +
    1. + podania błędnych lub niepełnych danych i informacji, +
    2. +
    3. + podejrzenia Usługobiorcy i/lub Użytkownika o bezprawne korzystanie z Serwisu lub w sposób + niezgodny z niniejszym Regulaminem, +
    4. +
    5. + braku opłaty za Usługi odpłatne, +
    6. +
    7. + innych istotnych przyczyn uniemożliwiających świadczenie Usług przez Usługodawcę, o których + Usługobiorca zostanie poinformowany.

      W przypadkach powyżej opisanych Usługodawca + nie ma obowiązku zwrotu uiszczonej przez Usługobiorcę opłaty, o ile taka opłata została + dokonana. +
    8. +
    +
  6. +
  7. + Usługodawca zastrzega sobie możliwość wyboru i zmiany rodzaju, form, czasu oraz sposobu udzielania + dostępu do Serwisu i Usług, o czym poinformuje Usługobiorców w sposób właściwy dla zmiany Regulaminu. +
  8. +
  9. + Usługodawca jest uprawniony do przerw lub zakłóceń w świadczeniu Usług drogą elektroniczną i + udostępniania Serwisu, jeśli powodem jest: +
      +
    1. + modernizacja, modyfikacja, konserwacja lub rozbudowa systemu teleinformatycznego lub + oprogramowania Usługodawcy; +
    2. +
    3. + działania niezależnych od Usługodawcy osób trzecich, w tym siła wyższa. +
    4. +
    +
  10. +
  11. + Usługodawca nie ponosi odpowiedzialności za brak możliwości lub utrudnienia w korzystaniu z Serwisu, + wynikające z przyczyn leżących po stronie Usługobiorcy. +
  12. +
  13. + Usługodawca ma prawo w każdym czasie zamknąć Serwis i zakończyć świadczenie Usług. +
  14. +
+

§ 13. ODPOWIEDZIALNOŚĆ USŁUGODAWCY

+
    +
  1. + Ani Usługobiorca, ani inne osoby, na rzecz których świadczone są Usługi, nie mogą żądać od + Usługodawcy, na podstawie umowy, ustawy lub na jakiejkolwiek innej podstawie, odszkodowania z tytułu + utraconych korzyści lub szkód następczych, ubocznych lub pośrednich związanych z roszczeniami + wynikającymi z niniejszej Umowy, w tym korzystania z Serwisu lub w inny sposób związanymi ze + świadczonymi przez Usługodawcę Usługami, niezależnie od tego, czy prawdopodobieństwo poniesienia takiej + straty lub szkody było przewidywane, czy też nie. +
  2. +
  3. + Ani Usługobiorca, ani inne osoby, na rzecz których świadczone są odpłatne Usługi, nie mogą żądać + od Usługodawcy, na podstawie umowy, ustawy lub na jakiejkolwiek innej podstawie, odszkodowania, którego + łączna wysokość przekraczałaby dwukrotność opłaty zapłaconej za odpłatną Usługę. +
  4. +
  5. + Odpowiedzialność Usługodawcy wobec Usługobiorcy za Usługi bezpłatne oferowane w Serwisie jest + wyłączona. +
  6. +
  7. + W przypadku, gdyby Usługodawca odpowiadał wobec Usługobiorcy lub wobec jakichkolwiek innych osób, na + rzecz których świadczone są odpłatne Usługi, na podstawie niniejszej Umowy lub na innej podstawie w + związku ze świadczonymi przez Usługodawcę Usługami, za stratę lub szkodę, do powstania której + przyczyniły się także inne osoby, odpowiedzialność Usługodawcy wobec Usługobiorcy będzie indywidualna, a + nie solidarna z tymi osobami, i będzie ograniczona do słusznego udziału Usługodawcy w całkowitej stracie + lub szkodzie, ustalonego w oparciu o stopień przyczynienia się Usługodawcy do powstania straty lub + szkody w relacji do innych osób, które się do niej przyczyniły. +
  8. +
  9. + Zastrzeżenia zawarte w ustępie 1 - 3 nie będą dotyczyć strat ani szkód wynikających z winy umyślnej + Usługodawcy, ani nie będą obowiązywać w zakresie, w jakim są niedozwolone w świetle obowiązujących + przepisów prawnych. +
  10. +
  11. + Usługobiorca nie może zgłaszać roszczeń ani wszczynać postępowania dotyczącego Usług lub w inny sposób + związanego z niniejszą Umową przeciwko jakiejkolwiek innej firmie z Grupy EY lub przeciwko + podwykonawcom, członkom, udziałowcom, członkom zarządu, przedstawicielom, partnerom, dyrektorom lub + pracownikom EY lub firmy z Grupy EY („Osoby EY”). Wszelkie roszczenia lub postępowania mogą zostać przez + Usługobiorcę zgłoszone lub wszczęte wyłącznie przeciwko Usługodawcy. +
  12. +
  13. + W najpełniejszym możliwym zakresie dozwolonym przez prawo i regulacje zawodowe, Usługobiorca zabezpieczy + Usługodawcę przed wszelkimi roszczeniami osób trzecich oraz wynikającymi z nich zobowiązaniami, + stratami, odszkodowaniami, kosztami i wydatkami powstałymi w związku z nieuprawnionym dostępem do + Serwisu przez tą osobę trzecią lub w związku z wykorzystaniem lub oparciem się przez stronę trzecią na + treściach zamieszczonych w Serwisie, ujawnionej takiej osobie przez Usługobiorcę, za pośrednictwem + Usługobiorcy lub na żądanie Usługobiorcy. +
  14. +
+

§ 14. POUFNOŚĆ

+
    +
  1. + O ile nie zezwalają na to inne postanowienia niniejszego Regulaminu, żadna ze Stron nie może ujawnić + stronom trzecim tajemnicy przedsiębiorstwa drugiej Strony. Każda ze Stron może jednak ujawnić takie + informacje w zakresie, w jakim informacje te: +
      +
    1. + są lub stały się znane opinii publicznej w inny sposób niż na skutek naruszenia postanowień + niniejszego Regulaminu, +
    2. +
    3. + zostały następnie uzyskane przez ich odbiorcę od strony trzeciej, która, zgodnie z wiedzą + odbiorcy, nie jest zobowiązana do zachowania poufności tych informacji wobec ujawniającej je + strony, +
    4. +
    5. + były znane odbiorcy tych informacji w momencie ich ujawnienia lub zostały później niezależnie + utworzone, +
    6. +
    7. + zostały ujawnione w celu wyegzekwowania praw przysługujących odbiorcy tych informacji na + podstawie niniejszej Umowy, +
    8. +
    9. + muszą zostać ujawnione na podstawie obowiązujących przepisów prawnych, procedur sądowych lub + regulacji zawodowych. +
    10. +
    +
  2. +
  3. + O ile nie zabraniają tego przepisy prawne, Usługodawca ma prawo ujawnić informacje Usługobiorcy i + Użytkownika innym spółkom z grupy Usługodawcy, pracownikom i współpracownikom oraz osobom trzecim + świadczącym usługi na rzecz Usługodawcy, które to podmioty mogą uzyskiwać, wykorzystywać, przekazywać, + gromadzić lub w inny sposób przetwarzać te informacje (łącznie: „Przetwarzać”) w różnych krajach, w + których prowadzą działalność, w celach związanych ze świadczeniem Usług, dostosowania się do wymogów + regulacyjnych, sprawdzenia, czy nie występuje konflikt interesów, dla celów związanych z jakością, + zarządzaniem ryzykiem lub rachunkowością finansową, lub w celu świadczenia innych usług wsparcia + administracyjnego (łącznie: „Cele Przetwarzania”). Usługodawca będzie wobec Usługobiorcy odpowiedzialny + za utrzymanie informacji Usługobiorcy w poufności. +
  4. +
+

§ 15. DANE OSOBOWE I COOKIES

+
    +
  1. + Poprzez akceptację Regulaminu i chęć korzystania z Serwisu, Usługobiorca i Użytkownik wyrażają zgodę + wobec Usługodawcy oraz podmiotów wskazanych w ust. 5 na przetwarzanie danych zamieszczonych formularzu + rejestracyjnym w celu aktywnego udziału w Serwisie zgodnie z obowiązującymi przepisami prawa. +
  2. +
  3. + Usługobiorca i Użytkownik wyrażają zgodę wobec Usługodawcy oraz podmiotów wskazanych w ust. 5 na + przetwarzanie danych zamieszczonych w formularzu rejestracyjnym dla celów przesyłania i otrzymywania + informacji handlowych oraz marketingu bezpośredniego drogą elektroniczną na podany adres poczty + elektronicznej. +
  4. +
  5. + Usługobiorca i Użytkownik wrażają zgodę wobec Usługodawcy oraz podmiotów wskazanych w ust. 5 na używanie + telekomunikacyjnych urządzeń końcowych, których Usługobiorca jest użytkownikiem, dla celów marketingu + bezpośredniego. +
  6. +
  7. + Usługobiorca i Użytkownik wrażają zgodę na ujawnienie przez Usługodawcę ich danych osobowych podmiotom + współorganizującym Usługi w Serwisie („Partnerzy Usługodawcy”) w celach przesyłania i otrzymywania + informacji handlowych oraz marketingu bezpośredniego drogą elektroniczną od tych Partnerów Usługodawcy. + W momencie ujawnienia danych osobowych Usługobiorcy i Użytkownika, Partner Usługodawcy staje się ich + administratorem i do niego Usługobiorca i Użytkownik powinni kierować zapytania związane z + przetwarzaniem danych osobowych. +
  8. +
  9. + Administratorem danych osobowych Usługobiorcy i Użytkownika jest Usługodawca lub może być jedna ze + spółek z globalnej organizacji firm członkowskich Ernst & Young Global Limited, z których każda jest + odrębnym podmiotem prawnym. Dane kontaktowe Usługodawcy oraz Spółek z Grupy Usługodawcy znajdują się pod + tym linkiem + https://assets.ey.com/content/dam/ey-sites/ey-com/en_gl/generic/ey-member-firms-and-affiliates.pdf. +
  10. +
  11. + Odbiorcą danych osobowych są pracownicy i współpracownicy oraz podmioty wspomagające Usługodawcę oraz + Spółki z Grupy EY w ich biznesowej działalności. +
  12. +
  13. + Dane osobowe Usługobiorcy i Użytkownika korzystających z Usług będą przechowywane w celach związanych z + dostępem do Serwisu oraz realizacją Usług przez Usługodawcę oraz marketingu bezpośredniego produktów lub + usług Spółek z Grupy EY, a także w celu przesyłania informacji handlowych. Podstawą prawną przetwarzania + danych osobowych, jest artykuł 6 ust. 1 lit. a) lub b) lub f) Rozporządzenia Parlamentu Europejskiego i + Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z + przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych (RODO). +
  14. +
  15. + Przetwarzane kategorie danych osobowych Usługobiorcy i Użytkownika to dane osobowe, które pochodzą + bezpośrednio od Usługobiorcy i Użytkownika (lub zostały przekazane w imieniu Usługobiorcy i Użytkownika) + lub dane osobowe, które zostały zebrane ze źródeł publicznie dostępnych, w szczególności: imię i + nazwisko, adres e-mail, telefon kontaktowy, adres korespondencyjny. +
  16. +
  17. + Dane osobowe przechowywane i przetwarzane będą do czasu zgłoszenia przez Usługobiorcę lub Użytkownika + żądania ich usunięcia lub ograniczenia przetwarzania lub wniesienia sprzeciwu wobec przetwarzania, a + także żądania ich przeniesienia. +
  18. +
  19. + Dane osobowe przechowywane dla celów przesyłania informacji handlowych oraz marketingu bezpośredniego + będą przechowywane i przetwarzane do czasu cofnięcia przez Usługobiorcę lub Użytkownika zgody na ich + przetwarzanie bądź żądania usunięcia lub ograniczenia przetwarzania lub wniesienia sprzeciwu wobec + przetwarzania, a także żądania ich przeniesienia. +
  20. +
  21. + Usługobiorca i Użytkownik ma prawo dostępu do swoich danych osobowych, ich sprostowania, usunięcia lub + ograniczenia przetwarzania lub ma prawo do wniesienia sprzeciwu wobec przetwarzania, a także prawo do + przenoszenia danych., w tym celu Usługobiorca i Użytkownik, są proszeni o kontakt z Usługodawcą na adres + e-mail: ey.tax@pl.ey.com. W przypadku wyrażenia przez Usługobiorcę lub Użytkownika zgody na + przetwarzanie danych osobowych, Usługobiorca lub Użytkownik ma prawo do cofnięcia zgody w dowolnym + momencie bez wpływu na zgodność z prawem przetwarzania. +
  22. +
  23. + Dane osobowe przekazane Usługodawcy podawane są mu dobrowolnie, z tym jednak zastrzeżeniem, że + niepodanie określonych w Formularzu danych w procesie rejestracji uniemożliwia wykonanie Usługi przez + Usługodawcę oraz korzystanie z Serwisu przez Usługobiorcę. +
  24. +
  25. + Usługobiorca ma prawo wnieść skargę do organu nadzorczego w zakresie przetwarzania danych osobowych. +
  26. +
  27. + Kontakt do inspektora danych osobowych: kontaktdaneosoboweEYPolska@pl.ey.com. +
  28. +
  29. + W przypadku wprowadzenia do Serwisu danych osobowych przez Usługobiorcę lub Użytkownika, które nie + dotyczą Usługobiorcy lub Użytkownika lub wprowadzenia danych osobowych Usługobiorcy lub Użytkownika + przez osobę trzecią, Usługobiorcą lub Użytkownik lub osoba trzecia zobowiązuje się w imieniu Usługodawcy + dopełnić wobec takich podmiotów obowiązku informacyjnego zgodnie z ust. 4-13 niniejszego paragrafu. +
  30. +
  31. + Prowadzony przez Usługodawcę Serwis i/lub każda z jej sekcji może wykorzystywać tzw. pliki cookies. + Dzięki technologii „cookies”, Serwis może przechowywać w przeglądarce użytkownika znaczniki informacji + („identyfikatory”), z których korzysta jedynie podczas wizyty Usługobiorcy na stronach Serwisu. + „Cookies” nie są wykorzystywane do określenia tożsamości żadnej z osób odwiedzających Serwis (chyba, że + Usługobiorca wyrazi na to zgodę), lecz pomagają śledzić ogólny ruch Usługobiorców na Serwisie, aby + ustalić preferowaną lokalizację i język Usługobiorcy i dzięki temu skierować go na odpowiednią stronę + Serwisu. +
  32. +
  33. + Jeżeli Usługobiorca nie chce otrzymywać plików cookies z Serwisu, może włączyć w przeglądarce opcję + powiadamiania o otrzymywanych plikach cookies i za każdym razem decydować o ich ewentualnym blokowaniu. + Należy jednak pamiętać, że wyłączenie otrzymywania „cookies” w przeglądarce może uniemożliwić + korzystanie z Serwisu. +
  34. +
+

§ 16. WŁASNOŚĆ INTELEKTUALNA

+
    +
  1. + Treść zamieszczone w Serwisie, Usługi mogą stanowić utwór w rozumieniu ustawy z dnia 4 lutego 1994 r. o + prawie autorskim i prawach pokrewnych . +
  2. +
  3. + Usługobiorca nie będzie używał nazwy (w tym logo) Usługodawcy ani jej części składowych w żadnych + materiałach promocyjnych lub kontaktach z osobami trzecimi bez uprzedniej pisemnej zgody Usługodawcy. +
  4. +
  5. + Wszelkie prawa do Serwisu oraz wszystkie treści zamieszczone w Serwisie (w tym Regulamin) korzystają z + ochrony na podstawie ustawy o prawie autorskim i prawach pokrewnych i są własnością Usługodawcy. +
  6. +
  7. + Jakiekolwiek naruszenie powyższych praw Usługodawcy może skutkować odpowiedzialnością cywilną oraz + karną. +
  8. +
+

§ 17. POSTANOWIENIA KOŃCOWE

+
    +
  1. + Niniejszy Regulamin obowiązuje od dnia zamieszczenia go w Serwisie Usługodawcy. +
  2. +
  3. + Regulamin jest dostępny w języku polskim +
  4. +
  5. + Regulamin jest udostępniany nieodpłatnie za pośrednictwem Serwisu. +
  6. +
  7. + Korzystanie z Serwisu podlegają prawu polskiemu i jurysdykcji sądów polskich. W sprawach + nieuregulowanych w niniejszym Regulaminie mają zastosowanie przepisy: Kodeksu cywilnego; Ustawy o + świadczeniu usług drogą elektroniczną z dnia 18 lipca 2002 r.; oraz inne właściwe przepisy prawa + polskiego. +
  8. +
  9. + Wszelkie spory dotyczące Serwisu lub świadczonych przez Usługodawcę Usług będą podlegać wyłącznej + jurysdykcji sądu właściwego ze względu na siedzibę Usługodawcy. +
  10. +
  11. + Prawa i obowiązki wynikające z korzystania z Serwisu nie mogą być scedowane lub w inny sposób + przeniesione na osoby trzecie bez uprzedniej pisemnej zgody Usługodawcy. +
  12. +
  13. + Zmiany dokonane w Regulaminie Serwisu przez Usługodawcę wiążą Usługobiorcę, pod warunkiem iż został on + prawidłowo poinformowany o zmianach i mógł się z nimi zapoznać. +
  14. +
  15. + W przypadku nieważności któregokolwiek postanowienia Regulaminu pozostałe postanowienia pozostają w + mocy. Postanowienia nieważne Strony zastąpią postanowieniami ważnymi zbliżonymi, w stopniu dozwolonym + przez prawo, do postanowień nieważnych oraz oddającymi pierwotne intencje Stron. +
  16. +
+
+ +{% endblock %} diff --git a/client/src/app.js b/client/src/app.js index c06eaf4..2b563c9 100644 --- a/client/src/app.js +++ b/client/src/app.js @@ -1,5 +1,3 @@ -import "./shared/form-navigation.js"; -import "./login-form.js"; import "./ow-account/ow-account.js"; import "./local-businesses/local-businesses.js"; @@ -12,6 +10,7 @@ import "./shared/nav/ow-path.js"; import "./shared/price/price-view"; import "./shared/price/price-input"; +import "./login-form.js"; import "./register-form.js"; import "./business-items/business-item"; @@ -21,6 +20,7 @@ import "./news/ow-articles"; import "./news/news-article"; import "./shared/rich-text-editor"; +import "./shared/form-navigation.js"; import "./contacts/contact-info-list"; import "./contacts/contact-info"; @@ -28,6 +28,12 @@ import "./contacts/contact-info-editor"; import "./contacts/contact-type-icon"; import "./contacts/edit-contact-info"; +import "./offers/marketplace-offer"; +import "./offers/marketplace-offers"; +import "./offers/offer-form"; + +import "./terms_and_conditions/terms-and-conditions"; + import { fireFbReady } from "./shared.js"; if (!document.querySelector('#facebook-jssdk')) { diff --git a/client/src/contacts/contact-info-editor.js b/client/src/contacts/contact-info-editor.js index 7cd9019..d5dd1fe 100644 --- a/client/src/contacts/contact-info-editor.js +++ b/client/src/contacts/contact-info-editor.js @@ -27,14 +27,6 @@ customElements.define('contact-info-editor', class extends Component {
-
- - -
@@ -43,6 +35,7 @@ customElements.define('contact-info-editor', class extends Component {
+
@@ -60,7 +53,6 @@ customElements.define('contact-info-editor', class extends Component { const input = this.shadowRoot.querySelector('#content'); input.addEventListener('change', ev => { ev.stopPropagation(); - console.log('change', input.value) this.#updateContactType(input.value, null); }); input.addEventListener('keyup', ev => { @@ -68,7 +60,6 @@ customElements.define('contact-info-editor', class extends Component { if (timeout) clearTimeout(timeout); timeout = setTimeout(() => { timeout = null; - console.log('keyup', input.value) this.#updateContactType(input.value, null); }, 1000 / 3) }); @@ -143,6 +134,9 @@ customElements.define('contact-info-editor', class extends Component { if (s.match(/http(s)?:\/\/(www\.)?facebook\.com/)) { return 'facebook'; } + if (s.match(/(\+\d{2,3} )?\d{3}([ \-])?\d{3}([ \-])?\d{3}/)) { + return 'mobile'; + } if (s.match(/^[a-zA-Z\d.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z\d-]+(?:\.[a-zA-Z\d-]+)*$/)) { return 'email'; } diff --git a/client/src/contacts/contact-info.js b/client/src/contacts/contact-info.js index a641478..a92f8d8 100644 --- a/client/src/contacts/contact-info.js +++ b/client/src/contacts/contact-info.js @@ -1,13 +1,12 @@ import { Component } from "../shared"; -customElements.define('contact-info', - class extends Component { - static get observedAttributes() { - return ['contact-type', 'content', 'contact-id', 'mode']; - } +customElements.define('contact-info', class extends Component { + static get observedAttributes() { + return ['contact-type', 'content', 'contact-id', 'mode']; + } - constructor() { - super(` + constructor() { + super(` @@ -31,6 +34,15 @@ customElements.define('contact-type-icon', + + + + + + + + + `); } diff --git a/client/src/offers/marketplace-offer.js b/client/src/offers/marketplace-offer.js new file mode 100644 index 0000000..332aa64 --- /dev/null +++ b/client/src/offers/marketplace-offer.js @@ -0,0 +1,14 @@ +import { Component } from "../shared"; + +customElements.define('marketplace-offer', class extends Component { + constructor() { + super(` + + + `); + } +}); diff --git a/client/src/offers/marketplace-offers.js b/client/src/offers/marketplace-offers.js new file mode 100644 index 0000000..7032f40 --- /dev/null +++ b/client/src/offers/marketplace-offers.js @@ -0,0 +1,14 @@ +import { Component } from "../shared"; + +customElements.define('marketplace-offers', class extends Component { + constructor() { + super(` + + + `); + } +}); diff --git a/client/src/offers/offer-form.js b/client/src/offers/offer-form.js new file mode 100644 index 0000000..0032797 --- /dev/null +++ b/client/src/offers/offer-form.js @@ -0,0 +1,79 @@ +import { Component, FORM_STYLE } from "../shared"; + +customElements.define('offer-form', class extends Component { + static get observedAttributes() { + return ['offer-id', 'description', 'picture-url'] + } + + constructor() { + super(` + +
+
+
+ + +
+
+ + +
+
+ +
+ +
+ `); + + this.addEventListener('image-input:uploaded', ev => { + console.log(ev); + }); + } + + get offer_id() { + const v = parseInt(this.getAttribute('offer-id')); + return isNaN(v) ? null : v; + } + + set offer_id(v) { + v = parseInt(v); + this.setAttribute('offer-id', v); + if (isNaN(v)) { + this.#removeId(); + } else { + this.#addId(v) + } + } + + get description() { + return this.getAttribute('description'); + } + + set description(v) { + this.setAttribute('description', v); + this.shadowRoot.querySelector('#description').value = v; + } + + #removeId() { + const form = this.shadowRoot.querySelector('form'); + const input = form.querySelector('#offer-id'); + input && input.remove(); + form.action = '/offers/create'; + form.querySelector('input[type=submit]').value = 'Utwórz'; + } + + #addId(v) { + this.#removeId(); + const form = this.shadowRoot.querySelector('form'); + const input = form.appendChild(document.createElement('input')); + input.setAttribute('type', 'hidden'); + input.setAttribute('name', 'id'); + input.setAttribute('id', 'offer-id'); + input.value = v; + form.action = '/offers/update'; + form.querySelector('input[type=submit]').value = 'Zmień'; + } +}); diff --git a/client/src/register-form/register-user-type.js b/client/src/register-form/register-user-type.js index 3320bd2..84839b6 100644 --- a/client/src/register-form/register-user-type.js +++ b/client/src/register-form/register-user-type.js @@ -1,4 +1,4 @@ -import { Component } from "../shared"; +import { Component, BUTTON_STYLE } from "../shared"; customElements.define('register-user-type', class extends Component { constructor() { @@ -36,14 +36,47 @@ customElements.define('register-user-type', class extends Component { width: 96px; height: 96px; } + button#accept-terms { + width: 80%; + height: auto; + display: block; + margin: auto auto 16px; + } + button#accept-terms > a { + border: none; + text-decoration: underline; + } @media only screen and (min-device-width: 1200px) { svg { width: 200px; height: 200px; } } + ${ BUTTON_STYLE } + `); + + const article = this.shadowRoot.querySelector('article'); + article.querySelector('button').addEventListener('click', ev => { + ev.stopPropagation(); + ev.preventDefault(); + + this.#termsAccepted(); + }) + } + + #termsAccepted() { + const article = this.shadowRoot.querySelector('article'); + + article.innerHTML = ` - - `); + `; const user = this.shadowRoot.querySelector('#user'); user.addEventListener('click', ev => { diff --git a/client/src/shared/image-input.js b/client/src/shared/image-input.js index 376b526..d323e2f 100644 --- a/client/src/shared/image-input.js +++ b/client/src/shared/image-input.js @@ -15,7 +15,7 @@ customElements.define('image-input', class extends Component { } #hidden { overflow: hidden; width: 1px; height: 1px; position: relative; } input[type=file] { position: absolute; top: -10px; left: -10px; display: none; } - #view { width: 200px; height: 200px; cursor: pointer; } + #view { height: 200px; cursor: pointer; } canvas { width: 200px; height: 200px; } div > input[type=button] { margin: 0; @@ -45,26 +45,7 @@ customElements.define('image-input', class extends Component { this.shadowRoot.querySelector('#save').addEventListener('click', ev => { ev.preventDefault(); ev.stopPropagation(); - const c = document.createElement('canvas'); - c.width = this.width; - c.height = this.height; - c.getContext('2d').putImageData(ctx.getImageData(0, 0, this.width, this.height), 0, 0); - - const blobBin = atob(c.toDataURL("image/webp", 1.0).split(',')[1]); - const array = []; - for (let i = 0; i < blobBin.length; i++) { - array.push(blobBin.charCodeAt(i)); - } - const file = new Blob([new Uint8Array(array)], { type: 'image/webp' }); - const form = new FormData; - form.append(`${ crypto.randomUUID() }.webp`, file); - fetch("/upload", { - method: "POST", - body: form, - }).then(res => res.json()).then(({ path }) => { - this.url = path; - this.dispatchEvent(new CustomEvent('image-input:uploaded', { bubbles: true, composed: true })); - }); + this.#uploadBase64(this.width, this.height); }); const f = new FileReader(); @@ -109,6 +90,7 @@ customElements.define('image-input', class extends Component { } connectedCallback() { + super.connectedCallback(); this.account_id = this.account_id; this.url = this.url; } @@ -132,6 +114,7 @@ customElements.define('image-input', class extends Component { set width(v) { this.setAttribute('width', v); + this.shadowRoot.querySelector('canvas').width = v; } get height() { @@ -141,6 +124,7 @@ customElements.define('image-input', class extends Component { set height(v) { this.setAttribute('height', v); + this.shadowRoot.querySelector('canvas').height = v; } get url() { @@ -152,4 +136,61 @@ customElements.define('image-input', class extends Component { this.setAttribute('url', v); this.shadowRoot.querySelector('img').src = v; } + + #uploadBase64(width, height) { + const canvas = this.shadowRoot.querySelector('canvas'); + const ctx = canvas.getContext('2d'); + const c = document.createElement('canvas'); + c.width = width; + c.height = height; + c.getContext('2d').putImageData(ctx.getImageData(0, 0, width, height), 0, 0); + + const blobBin = atob(c.toDataURL("image/webp", 1.0).split(',')[1]); + const array = []; + for (let i = 0; i < blobBin.length; i++) { + array.push(blobBin.charCodeAt(i)); + } + const file = new Blob([new Uint8Array(array)], { type: 'image/webp' }); + const form = new FormData; + form.append(`${ crypto.randomUUID() }.webp`, file); + fetch("/upload", { + method: "POST", + body: form, + }).then(res => res.json()).then(({ path }) => { + this.url = path; + this.dispatchEvent(new CustomEvent('image-input:uploaded', { bubbles: true, composed: true })); + }); + } }); + +customElements.define('upload-size', class extends Component { + static get observedAttributes() { + return ['width', 'height']; + } + + constructor() { + super(``); + } + + get width() { + const v = parseInt(this.getAttribute('width')); + return isNaN(v) ? 0 : v; + } + + set width(v) { + this.setAttribute('width', v); + } + + get height() { + const v = parseInt(this.getAttribute('height')); + return isNaN(v) ? 0 : v; + } + + set height(v) { + this.setAttribute('height', v); + } + + get size() { + return { width: this.width, height: this.height } + } +}) diff --git a/client/src/terms_and_conditions/terms-and-condition-rule.js b/client/src/terms_and_conditions/terms-and-condition-rule.js new file mode 100644 index 0000000..1d2be1d --- /dev/null +++ b/client/src/terms_and_conditions/terms-and-condition-rule.js @@ -0,0 +1,14 @@ +import { Component } from "../shared"; + +customElements.define('terms-and-condition-rule', class extends Component { + constructor() { + super(` + + + `); + } +}); diff --git a/client/src/terms_and_conditions/terms-and-conditions.js b/client/src/terms_and_conditions/terms-and-conditions.js new file mode 100644 index 0000000..69da761 --- /dev/null +++ b/client/src/terms_and_conditions/terms-and-conditions.js @@ -0,0 +1,14 @@ +import { Component } from "../shared"; + +customElements.define('terms-and-conditions', class extends Component { + constructor() { + super(` + + + `); + } +}); diff --git a/migrations/20220718083942_add_full_text_search.sql b/migrations/20220718083942_add_full_text_search.sql new file mode 100644 index 0000000..1577379 --- /dev/null +++ b/migrations/20220718083942_add_full_text_search.sql @@ -0,0 +1,2 @@ +ALTER TABLE offers + ADD COLUMN search tsvector; diff --git a/migrations/20220718085052_add_descr.sql b/migrations/20220718085052_add_descr.sql new file mode 100644 index 0000000..922d45e --- /dev/null +++ b/migrations/20220718085052_add_descr.sql @@ -0,0 +1,2 @@ +ALTER TABLE offers + ADD COLUMN description text; diff --git a/migrations/20220718124818_add_offer_owner.sql b/migrations/20220718124818_add_offer_owner.sql new file mode 100644 index 0000000..a50a1d2 --- /dev/null +++ b/migrations/20220718124818_add_offer_owner.sql @@ -0,0 +1,2 @@ +ALTER TABLE offers + ADD COLUMN owner_id INT REFERENCES accounts (id) NOT NULL; diff --git a/src/model/db.rs b/src/model/db.rs index 9787803..f5a8bdd 100644 --- a/src/model/db.rs +++ b/src/model/db.rs @@ -6,29 +6,14 @@ use serde::{Deserialize, Serialize}; use sqlx::{FromRow, Type}; use uuid::Uuid; -#[derive(Debug, PartialOrd, PartialEq, Eq, Copy, Clone, Serialize, Deserialize, Type)] +#[derive(Debug, Default, PartialOrd, PartialEq, Eq, Copy, Clone, Serialize, Deserialize, Type)] pub enum AccountType { + #[default] User = 1, Business = 10, Admin = 100, } -#[derive(Debug, Serialize, Deserialize, FromRow)] -pub struct Account { - pub id: i32, - pub login: String, - pub email: String, - pub pass: String, - pub facebook_id: Option, - pub account_type: AccountType, -} - -#[derive(Debug, Serialize, Deserialize, Type)] -pub enum Role { - User, - Admin, -} - #[derive(Debug, Default, Copy, Clone, Serialize, Deserialize, Type)] pub enum LocalBusinessState { #[default] @@ -39,6 +24,24 @@ pub enum LocalBusinessState { Internal, } +#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize, Type)] +pub enum OfferState { + #[default] + Pending, + Approved, + Banned, +} + +#[derive(Debug, Serialize, Deserialize, FromRow)] +pub struct Account { + pub id: i32, + pub login: String, + pub email: String, + pub pass: String, + pub facebook_id: Option, + pub account_type: AccountType, +} + impl Display for LocalBusinessState { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(self.as_str()) @@ -86,7 +89,7 @@ pub struct Token { pub nbt: NaiveDateTime, /* not before time */ pub iat: NaiveDateTime, /* issued at time */ pub jti: Uuid, /* JWT ID - unique */ - pub role: Role, + pub role: AccountType, } #[derive(Debug, Default, Serialize, Deserialize, FromRow)] @@ -162,6 +165,16 @@ pub struct UpdateLocalBusinessInput { pub description: String, } +#[derive(Debug, Serialize, Deserialize, FromRow)] +pub struct Offer { + pub id: i32, + pub owner_id: i32, + pub description: String, + pub picture_url: String, + pub state: OfferState, + pub created_at: NaiveDateTime, +} + #[derive(Debug)] pub struct CreateLocalBusinessItemInput { pub local_business_id: i32, @@ -209,3 +222,19 @@ pub struct CreateAccountInput { pub facebook_id: Option, pub account_type: AccountType, } + +#[derive(Debug)] +pub struct CreateOfferInput { + pub description: String, + pub picture_url: String, + pub state: OfferState, + pub owner_id: i32, +} + +#[derive(Debug)] +pub struct UpdateOfferInput { + pub id: i32, + pub description: String, + pub picture_url: String, + pub state: OfferState, +} diff --git a/src/model/view.rs b/src/model/view.rs index 8fef48c..eb84daa 100644 --- a/src/model/view.rs +++ b/src/model/view.rs @@ -10,8 +10,9 @@ pub enum Page { Account, Register, Login, - BusinessItems, + AccountBusinessItems, Marketplace, + AccountOffers, AdminNews, AdminCreateNews, AdminBusinesses, @@ -19,16 +20,7 @@ pub enum Page { impl Page { pub fn is_public(&self) -> bool { - matches!( - self, - Page::LocalBusinesses - | Page::News - | Page::Account - | Page::Register - | Page::Login - | Page::BusinessItems - | Page::Marketplace - ) + !self.is_admin() } pub fn is_admin(&self) -> bool { @@ -62,8 +54,8 @@ impl Page { } } - pub fn select_business_items(&self) -> &str { - if matches!(self, Page::BusinessItems) { + pub fn select_account_business(&self) -> &str { + if matches!(self, Page::AccountBusinessItems) { "selected" } else { "" @@ -93,6 +85,14 @@ impl Page { "" } } + + pub fn select_account_offers(&self) -> &str { + if matches!(self, Page::AccountOffers) { + "selected" + } else { + "" + } + } } #[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)] diff --git a/src/queries/mod.rs b/src/queries/mod.rs index 8e85162..20a7279 100644 --- a/src/queries/mod.rs +++ b/src/queries/mod.rs @@ -81,6 +81,15 @@ pub enum Error { UpdateContact { input: db::UpdateContactInput, }, + AllOffers, + AccountOffers, + VisibleOffers, + CreateOffer { + input: db::CreateOfferInput, + }, + UpdateOffer { + input: db::UpdateOfferInput, + }, } pub type Result = std::result::Result; @@ -979,3 +988,139 @@ RETURNING id, login, email, pass, facebook_id, account_type } }) } + +#[tracing::instrument] +pub async fn all_offers(t: &mut T<'_>) -> Result> { + sqlx::query_as( + r#" +SELECT + id, + owner_id, + name, + description, + picture_url, + state, + created_at +FROM offers + "#, + ) + .fetch_all(t) + .await + .map_err(|e| { + error!("{e}"); + dbg!(e); + Error::AllOffers + }) +} + +#[tracing::instrument] +pub async fn visible_offers(t: &mut T<'_>) -> Result> { + sqlx::query_as( + r#" +SELECT + id, + owner_id, + name, + description, + picture_url, + state, + created_at +FROM offers +WHERE created_at + '2 weeks' <= now() AND state = 'Approved' + "#, + ) + .fetch_all(t) + .await + .map_err(|e| { + error!("{e}"); + dbg!(e); + Error::VisibleOffers + }) +} + +#[tracing::instrument] +pub async fn account_offers(t: &mut T<'_>, account_id: i32) -> Result> { + sqlx::query_as( + r#" +SELECT + id, + owner_id, + description, + picture_url, + state, + created_at +FROM offers +WHERE owner_id = $1 + "#, + ) + .bind(account_id) + .fetch_all(t) + .await + .map_err(|e| { + error!("{e}"); + dbg!(e); + Error::AccountOffers + }) +} + +#[tracing::instrument] +pub async fn create_offer(t: &mut T<'_>, input: db::CreateOfferInput) -> Result { + sqlx::query_as( + r#" +INSERT INTO offers (description, picture_url, state, search, owner_id) +VALUES ($1, $2, $3, to_tsvector('polish', $4), $5) +RETURNING + id, + owner_id, + description, + picture_url, + state, + created_at + "#, + ) + .bind(&input.description) + .bind(&input.picture_url) + .bind(input.state) + .bind(&input.description) + .bind(input.owner_id) + .fetch_one(t) + .await + .map_err(|e| { + error!("{e}"); + dbg!(e); + Error::CreateOffer { input } + }) +} + +#[tracing::instrument] +pub async fn update_offer(t: &mut T<'_>, input: db::UpdateOfferInput) -> Result { + sqlx::query_as( + r#" +UPDATE offers +SET description = $2, + picture_url = $3, + state = $4, + search = to_tsvector('polish', $5) +WHERE id = $1 +RETURNING + id, + owner_id, + description, + picture_url, + state, + created_at + "#, + ) + .bind(input.id) + .bind(&input.description) + .bind(&input.picture_url) + .bind(input.state) + .bind(&input.description) + .fetch_one(t) + .await + .map_err(|e| { + error!("{e}"); + dbg!(e); + Error::UpdateOffer { input } + }) +} diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 20e694f..e2d58f0 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -51,8 +51,8 @@ macro_rules! not_xss { pub use unrestricted::render_index; pub fn configure(config: &mut ServiceConfig) { - unrestricted::configure(config); restricted::configure(config); + unrestricted::configure(config); } pub struct Identity(actix_identity::Identity); diff --git a/src/routes/restricted.rs b/src/routes/restricted.rs index 5983c2d..8916e3d 100644 --- a/src/routes/restricted.rs +++ b/src/routes/restricted.rs @@ -9,6 +9,7 @@ use crate::routes::{Identity, Result}; pub mod admin; mod business_item; mod contacts; +mod offers; use crate::view::Helper; @@ -77,7 +78,7 @@ async fn handle_business_items_page( let contacts = crate::ok_or_internal!(queries::account_contacts(t, account.id).await); let page = BusinessItemsTemplate { - page: view::Page::BusinessItems, + page: view::Page::AccountBusinessItems, account: Some(account), items, business, @@ -91,6 +92,7 @@ async fn handle_business_items_page( pub fn configure(config: &mut ServiceConfig) { config.service(business_items_page); + offers::configure(config); business_item::configure(config); contacts::configure(config); admin::configure(config); diff --git a/src/routes/restricted/offers.rs b/src/routes/restricted/offers.rs new file mode 100644 index 0000000..22b235c --- /dev/null +++ b/src/routes/restricted/offers.rs @@ -0,0 +1,47 @@ +use actix_web::web::{Data, ServiceConfig}; +use actix_web::{get, HttpResponse}; +use askama::*; +use sqlx::PgPool; + +use crate::model::db; +use crate::model::view::Page; +use crate::routes::{Identity, Result}; +use crate::view::Helper; +use crate::{authorize, ok_or_internal, queries}; + +#[derive(Default, Template)] +#[template(path = "./offers/index.html")] +struct AccountOffersTemplate { + account: Option, + error: Option, + page: Page, + h: Helper, + offers: Vec, +} + +#[get("/account/offers")] +pub async fn account_offers(id: Identity, db: Data) -> Result { + let pool = db.into_inner(); + let mut t = ok_or_internal!(pool.begin().await); + let account = authorize!(&mut t, id); + + let offers = queries::account_offers(&mut t, account.id) + .await + .unwrap_or_default(); + + t.commit().await.ok(); + + let body = AccountOffersTemplate { + account: Some(account), + offers, + page: Page::AccountOffers, + ..Default::default() + } + .render() + .unwrap(); + Ok(HttpResponse::Ok().content_type("text/html").body(body)) +} + +pub fn configure(config: &mut ServiceConfig) { + config.service(account_offers); +} diff --git a/src/routes/unrestricted.rs b/src/routes/unrestricted.rs index 83d35b7..1949560 100644 --- a/src/routes/unrestricted.rs +++ b/src/routes/unrestricted.rs @@ -2,6 +2,7 @@ mod account; mod businesses; mod marketplace; mod news; +mod terms; use actix_files::Files; use actix_web::web::ServiceConfig; @@ -37,6 +38,7 @@ pub async fn render_index() -> HttpResponse { pub fn configure(config: &mut ServiceConfig) { std::fs::create_dir_all("./uploads").expect("Failed to create ./uploads directory"); + terms::configure(config); account::configure(config); news::configure(config); marketplace::configure(config); diff --git a/src/routes/unrestricted/account.rs b/src/routes/unrestricted/account.rs index 20e0aa6..adbe364 100644 --- a/src/routes/unrestricted/account.rs +++ b/src/routes/unrestricted/account.rs @@ -32,10 +32,7 @@ impl AccountTemplate { } } - pub fn bad_request>( - error: Error, - page: Page, - ) -> routes::Result { + pub fn bad_request>(error: Error, page: Page) -> Result { Ok(HttpResponse::BadRequest().body(AccountTemplate::error(error, page).render().unwrap())) } } diff --git a/src/routes/unrestricted/marketplace.rs b/src/routes/unrestricted/marketplace.rs index 58a899e..79e2426 100644 --- a/src/routes/unrestricted/marketplace.rs +++ b/src/routes/unrestricted/marketplace.rs @@ -1,10 +1,12 @@ -use actix_web::web::{self, ServiceConfig}; +use actix_web::web::{self, Data, ServiceConfig}; use actix_web::{get, HttpResponse}; use askama::*; +use sqlx::PgPool; use crate::model::db; use crate::model::view::Page; -use crate::routes::Result; +use crate::queries; +use crate::routes::{Identity, Result}; use crate::view::Helper; #[derive(Default, Template)] @@ -14,13 +16,27 @@ struct MarketplaceTemplate { error: Option, page: Page, h: Helper, + offers: Vec, } #[get("")] -async fn marketplace() -> Result { +async fn marketplace(db: Data, id: Identity) -> Result { + let pool = db.into_inner(); + let mut t = crate::ok_or_internal!(pool.begin().await); + let account = match id.identity() { + Some(id) => queries::account_by_id(&mut t, id).await, + _ => None, + }; + + let offers = queries::visible_offers(&mut t).await.unwrap_or_default(); + + t.commit().await.ok(); + Ok(HttpResponse::Ok().body( MarketplaceTemplate { page: Page::Marketplace, + account, + offers, ..Default::default() } .render() diff --git a/src/routes/unrestricted/terms.rs b/src/routes/unrestricted/terms.rs new file mode 100644 index 0000000..072dae0 --- /dev/null +++ b/src/routes/unrestricted/terms.rs @@ -0,0 +1,25 @@ +use actix_web::web::ServiceConfig; +use actix_web::{get, HttpResponse}; +use askama::*; + +use crate::model::db; +use crate::model::view::Page; +use crate::view::Helper; + +#[derive(Default, Template)] +#[template(path = "terms-and-condition.html")] +pub struct TermsTemplate { + account: Option, + error: Option, + page: Page, + h: Helper, +} + +#[get("/terms-and-condition")] +pub async fn terms_and_condition() -> HttpResponse { + HttpResponse::Ok().body(TermsTemplate::default().render().unwrap()) +} + +pub fn configure(config: &mut ServiceConfig) { + config.service(terms_and_condition); +} diff --git a/src/view/mod.rs b/src/view/mod.rs index a2c9282..68ee51e 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -33,4 +33,16 @@ impl Helper { .map(|a| a.email.as_str()) .unwrap_or_default() } + + pub fn render_contact(&self, ty: &str, val: &str) -> String { + if ty == "mobile" { + self.mobile(val) + } else { + val.into() + } + } + + fn mobile(&self, phone: &str) -> String { + base64::encode(phone) + } }