Building Offers

This commit is contained in:
Adrian Woźniak 2022-07-18 16:23:07 +02:00
parent 883aa37e7c
commit d69c4bb6ef
No known key found for this signature in database
GPG Key ID: 0012845A89C7352B
33 changed files with 1410 additions and 151 deletions

1
Cargo.lock generated
View File

@ -1307,6 +1307,7 @@ dependencies = [
"actix-web",
"argon2",
"askama",
"base64",
"chrono",
"futures",
"futures-util",

View File

@ -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"

View File

@ -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;

View File

@ -62,7 +62,7 @@
</ow-path>
{% if h.is_above_user(account) %}
<ow-path path="/account/business-items" selected="{{ page.select_business_items() }}" title="Moje usługi">
<ow-path path="/account/business-items" selected="{{ page.select_account_business() }}" title="Moje usługi">
<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<path d="M25 26a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1V5h10V3H5v23a3 3 0 0 0 3 3h16a3 3 0 0 0 3-3V13h-2Z"/>
<path d="M27.12 2.88a3.08 3.08 0 0 0-4.24 0L17 8.75l-1 5.3L21.25 13l5.87-5.87a3 3 0 0 0 0-4.25Zm-6.86 8.27-1.76.35.35-1.76 3.32-3.33 1.42 1.42Zm5.45-5.44-.71.7L23.59 5l.7-.71a1 1 0 0 1 1.42 0 1 1 0 0 1 0 1.42Z"/>
@ -71,17 +71,22 @@
</ow-path>
{% endif %}
<ow-path path="/account/offers" selected="{{ page.select_account_offers() }}" title="Moje sprzedaże">
<svg viewBox="0 0 32 32" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
<path d="M30.412 19.045a.34.34 0 0 0-.34.341V30.83c0 .12-.102.222-.222.222h-2.627v-3.14h.87a.402.402 0 0 0 .372-.22.402.402 0 0 0-.054-.43l-1.818-2.346a.436.436 0 0 0-.346-.173h-.003a.437.437 0 0 0-.347.179l-1.758 2.343a.403.403 0 0 0-.049.429.403.403 0 0 0 .372.218h.806v3.14h-8.941a.594.594 0 0 1-.594-.594V19.716c0-.327.266-.594.594-.594H27.7a.34.34 0 1 0 0-.681H16.327c-.703 0-1.275.572-1.275 1.275v10.742c0 .703.572 1.275 1.275 1.275h9.282a.34.34 0 0 0 .34-.34V27.57a.34.34 0 0 0-.34-.34h-.592l1.233-1.645 1.274 1.645h-.642a.34.34 0 0 0-.34.34v3.821a.34.34 0 0 0 .34.34h2.968a.905.905 0 0 0 .903-.903V19.386a.34.34 0 0 0-.34-.34z"
/>
<path d="M17.52 15.715c-.638-.713-5.53-6.169-7.115-7.557 1.257-.794 2.022-2.14 2.022-3.61C12.427 2.168 10.42.23 7.952.23c-2.468 0-4.475 1.938-4.475 4.32 0 1.455.75 2.789 1.986 3.586-1.026.75-1.648 1.93-1.648 3.186v18.466c0 .971.819 1.761 1.825 1.761s1.824-.79 1.824-1.76V19.643h.938v10.143c0 .971.819 1.761 1.825 1.761s1.824-.79 1.824-1.76l.036-15.054 3.216 3.104c.304.294.704.44 1.104.44.4 0 .8-.146 1.104-.44a1.472 1.472 0 0 0 .008-2.123z"
/>
</svg>
</ow-path>
{% if h.is_admin(account) %}
<ow-path path="/admin" selected="{{ page.select_admin_news() }}" title="Admin">
<svg viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
<path d="M14.68 14.81a6.76 6.76 0 1 1 6.76-6.75 6.77 6.77 0 0 1-6.76 6.75Zm0-11.51a4.76 4.76 0 1 0 4.76 4.76 4.76 4.76 0 0 0-4.76-4.76Z"
class="clr-i-outline clr-i-outline-path-1"/>
<path d="M16.42 31.68A2.14 2.14 0 0 1 15.8 30H4v-5.78a14.81 14.81 0 0 1 11.09-4.68h.72a2.2 2.2 0 0 1 .62-1.85l.12-.11c-.47 0-1-.06-1.46-.06A16.47 16.47 0 0 0 2.2 23.26a1 1 0 0 0-.2.6V30a2 2 0 0 0 2 2h12.7Z"
class="clr-i-outline clr-i-outline-path-2"/>
<path d="M26.87 16.29a.37.37 0 0 1 .15 0 .42.42 0 0 0-.15 0Z"
class="clr-i-outline clr-i-outline-path-3"/>
<path d="m33.68 23.32-2-.61a7.21 7.21 0 0 0-.58-1.41l1-1.86A.38.38 0 0 0 32 19l-1.45-1.45a.36.36 0 0 0-.44-.07l-1.84 1a7.15 7.15 0 0 0-1.43-.61l-.61-2a.36.36 0 0 0-.36-.24h-2.05a.36.36 0 0 0-.35.26l-.61 2a7 7 0 0 0-1.44.6l-1.82-1a.35.35 0 0 0-.43.07L17.69 19a.38.38 0 0 0-.06.44l1 1.82a6.77 6.77 0 0 0-.63 1.43l-2 .6a.36.36 0 0 0-.26.35v2.05A.35.35 0 0 0 16 26l2 .61a7 7 0 0 0 .6 1.41l-1 1.91a.36.36 0 0 0 .06.43l1.45 1.45a.38.38 0 0 0 .44.07l1.87-1a7.09 7.09 0 0 0 1.4.57l.6 2a.38.38 0 0 0 .35.26h2.05a.37.37 0 0 0 .35-.26l.61-2.05a6.92 6.92 0 0 0 1.38-.57l1.89 1a.36.36 0 0 0 .43-.07L32 30.4a.35.35 0 0 0 0-.4l-1-1.88a7 7 0 0 0 .58-1.39l2-.61a.36.36 0 0 0 .26-.35v-2.1a.36.36 0 0 0-.16-.35ZM24.85 28a3.34 3.34 0 1 1 3.33-3.33A3.34 3.34 0 0 1 24.85 28Z"
class="clr-i-outline clr-i-outline-path-4"/>
<path d="M14.68 14.81a6.76 6.76 0 1 1 6.76-6.75 6.77 6.77 0 0 1-6.76 6.75Zm0-11.51a4.76 4.76 0 1 0 4.76 4.76 4.76 4.76 0 0 0-4.76-4.76Z"/>
<path d="M16.42 31.68A2.14 2.14 0 0 1 15.8 30H4v-5.78a14.81 14.81 0 0 1 11.09-4.68h.72a2.2 2.2 0 0 1 .62-1.85l.12-.11c-.47 0-1-.06-1.46-.06A16.47 16.47 0 0 0 2.2 23.26a1 1 0 0 0-.2.6V30a2 2 0 0 0 2 2h12.7Z"/>
<path d="M26.87 16.29a.37.37 0 0 1 .15 0 .42.42 0 0 0-.15 0Z"/>
<path d="m33.68 23.32-2-.61a7.21 7.21 0 0 0-.58-1.41l1-1.86A.38.38 0 0 0 32 19l-1.45-1.45a.36.36 0 0 0-.44-.07l-1.84 1a7.15 7.15 0 0 0-1.43-.61l-.61-2a.36.36 0 0 0-.36-.24h-2.05a.36.36 0 0 0-.35.26l-.61 2a7 7 0 0 0-1.44.6l-1.82-1a.35.35 0 0 0-.43.07L17.69 19a.38.38 0 0 0-.06.44l1 1.82a6.77 6.77 0 0 0-.63 1.43l-2 .6a.36.36 0 0 0-.26.35v2.05A.35.35 0 0 0 16 26l2 .61a7 7 0 0 0 .6 1.41l-1 1.91a.36.36 0 0 0 .06.43l1.45 1.45a.38.38 0 0 0 .44.07l1.87-1a7.09 7.09 0 0 0 1.4.57l.6 2a.38.38 0 0 0 .35.26h2.05a.37.37 0 0 0 .35-.26l.61-2.05a6.92 6.92 0 0 0 1.38-.57l1.89 1a.36.36 0 0 0 .43-.07L32 30.4a.35.35 0 0 0 0-.4l-1-1.88a7 7 0 0 0 .58-1.39l2-.61a.36.36 0 0 0 .26-.35v-2.1a.36.36 0 0 0-.16-.35ZM24.85 28a3.34 3.34 0 1 1 3.33-3.33A3.34 3.34 0 0 1 24.85 28Z"/>
<path fill="none" d="M0 0h36v36H0z"/>
</svg>
<div>Admin</div>
@ -97,7 +102,8 @@
</svg>
<div>Aktualności</div>
</ow-path>
<ow-path path="/admin/businesses" selected="{{ page.select_admin_businesses() }}" title="Zarządzaj usługami">
<ow-path path="/admin/businesses" selected="{{ page.select_admin_businesses() }}"
title="Zarządzaj usługami">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 511.999 511.999" xml:space="preserve">
<path d="M440.482 50.916c-8.099-4.226-18.091-1.088-22.321 7.013l-41.925 80.336-46.147 36.662h-54.683l-57.033-18.756-33.145-53.595 5.854-5.694c3.554-3.457 3.634-9.143.176-12.697l-13.735-14.12 10.294-10.014c4.024-3.914 4.113-10.35.198-14.374l-41.438-42.6c-3.914-4.024-10.35-4.113-14.374-.198l-66.5 64.687c-4.024 3.914-4.113 10.35-.198 14.374l41.438 42.599c3.914 4.024 10.35 4.113 14.374.198l10.294-10.013 13.737 14.121c3.449 3.547 9.136 3.64 12.696.176l2.896-2.817 32.466 52.499a16.544 16.544 0 0 0 8.901 7.014l58.436 19.218.008 287.213c0 10.964 8.888 19.853 19.852 19.853s19.852-8.888 19.852-19.853V333.466l8.565-2.239 24.462 64.136-17.398 78.459c-2.373 10.704 4.38 21.306 15.084 23.679 10.69 2.373 21.303-4.371 23.679-15.083l18.771-84.647a19.858 19.858 0 0 0-1.096-12.026l-24.153-57.154V202.66l51.197-40.674a16.547 16.547 0 0 0 4.375-5.299l43.551-83.45c4.23-8.1 1.089-18.094-7.01-22.321zM171.921 90.467a16.48 16.48 0 0 0-12.357 2.058c-6.031 3.73-8.81 10.704-7.514 17.272l-.092.088-7.475-7.683 20.167-19.617 7.475 7.684-.204.198z"/>
<circle cx="304.734" cy="129.707" r="34.286"/>

View File

@ -26,8 +26,8 @@
<contact-info
mode="icon"
contact-id="{{contact.id}}"
content="{{h.render_contact(contact.contact_type.as_str(), contact.content.as_str())}}"
contact-type="{{contact.contact_type}}"
content="{{contact.content}}"
></contact-info>
{% endfor %}
</contact-info-list>

View File

@ -1,3 +1,12 @@
{% extends "../base.html" %}
{% block content %}
<marketplace-offers>
{% for offer in offers %}
<marketplace-offer
offer-id="{{offer.id}}"
description="{{offer.description}}"
picture-url="{{offer.picture_url}}"
></marketplace-offer>
{% endfor %}
</marketplace-offers>
{% endblock %}

View File

@ -0,0 +1,13 @@
{% extends "../base.html" %}
{% block content %}
<marketplace-offers>
<offer-form></offer-form>
{% for offer in offers %}
<marketplace-offer
offer-id="{{offer.id}}"
description="{{offer.description}}"
picture-url="{{offer.picture_url}}"
></marketplace-offer>
{% endfor %}
</marketplace-offers>
{% endblock %}

View File

@ -0,0 +1,708 @@
{% extends "base.html" %}
{% block content %}
<terms-and-conditions>
<h1>REGULAMIN SERIWSU INTERNETOWEGO</h1>
<div>
<h3 style="text-align: center;">REGULAMIN SERIWSU INTERNETOWEGO<br> oswilno.pl</h3>
<p>&nbsp;</p>
<h3>§ 1. DEFINICJE</h3>
<ol>
<li>
Darmowy dostęp dostęp do funkcjonalności Serwisu określonych przez Usługodawcę, za które nie są
wymagane opłaty.
</li>
<li>
Osiedle - dzielnica Elsnerów w Warszawie.
</li>
<li>
Mieszkaniec - osoba zamieszkująca dzielnicę Elsnerów w Warszawie.
</li>
<li>
Upoważniony użytkownik - osoba zarejestrowana i nie będąca Mieszkańcem.
</li>
<li>
Gość - osoba niezarejestrowana korzystająca z serwisu.
</li>
<li>
Formularz formularz służący do rejestracji Usługobiorcy oraz zawarcia Umowy z Usługodawcą dostępny na
stronie internetowej oswilno.pl.
</li>
<li>
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.
</li>
<li>
Kodeks etyki Zasady Etyki Doradców Podatkowych, Zasady etyki zawodowej biegłych rewidentów, Kodeks
Etyki Adwokackiej oraz Kodeks Etyki Radcy Prawnego.
</li>
<li>
Konto - konto Usługobiorcy tworzone w procesie rejestracji w Serwisie, tworzone na potrzeby realizacji
wybranych Usług.
</li>
<li>
Regulamin - niniejszy regulamin Serwisu.
</li>
<li>
Serwis - Serwis internetowy Usługodawcy działający pod adresem oswilno.pl.
</li>
<li>
Usługa dostęp do Serwisu i funkcjonalności Serwisu, w tym w szczególności, ale nie wyłącznie dostęp
do:
<ul>
<li>zarządzanie ogłoszeniami usług dodanych przez Mieszkańcę lub Upoważnionego użytkownika</li>
<li>zarządzanie ogłoszeniami sprzedaży przez osoby prywatne zamieszkujące Osiedle</li>
<li>zarządzanie prywatnym Kontem</li>
</ul>
</li>
<li>
Usługobiorca Mieszkaniec, Gość lub Upoważniony użytkownik
</li>
<li>
Użytkownik Mieszkaniec lub Osoba upoważniona wskazany w Formularzu, która z ramienia Usługobiorcy ma
prawo do korzystania z Serwisu.
</li>
</ol>
<h3>§ 2. POSTANOWIENIA OGÓLNE</h3>
<ol>
<li>
Serwis prowadzony jest przez Usługodawcę. Adres e-mail Usługodawcy to:
<a href="mailto:adrian.wozniak@ita-prog.pl">adrian.wozniak@ita-prog.pl</a>.
</li>
<li>
Serwis działa na zasadach określonych w niniejszym Regulaminie oraz przepisach obowiązującego prawa.
</li>
<li>
Serwis ma na celu prezentację oferowanych usług przez Mieszkańców.
</li>
<li>
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.
</li>
<li>
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ść.
</li>
<li>
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.
</li>
</ol>
<h3>§ 3. WARUNKI ŚWIADCZONYCH USŁUG</h3>
<ol>
<li>1. Za pośrednictwem Serwisu Usługodawca umożliwia:
<ol>
<li>rejestrację Usługobiorcy w Serwisie,</li>
<li>korzystanie przez Usługobiorcę i Użytkownika z Serwisu.</li>
</ol>
</li>
<li>
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ń.
</li>
<li>
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.
</li>
<li>
Usługodawca określa następujące wymagania techniczne w celu korzystania z Serwisu:
<ol>
<li>Komputer z dostępem do Internetu.</li>
<li>Dostęp do e-mail.</li>
<li>Przeglądarka internetowa.</li>
<li>Włączenie w przeglądarce internetowej Cookies oraz Javascript.</li>
</ol>
</li>
<li>
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.
</li>
<li>
Usługodawca dokłada starań aby Serwis był należycie zabezpieczony.
</li>
<li>
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ą.
</li>
<li>
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.
</li>
</ol>
<h3>§ 4. REJESTRACJA</h3>
<ol>
<li>
Dostęp i korzystanie z Serwisu przez Usługobiorcę jest bezpłatny.
</li>
<li>
Dostęp i korzystanie z Serwisu Usługobiorca otrzymuje na czas nieokreślony.
</li>
<li>Rejestracja odbywa się w następujący sposób:
<ol>
<li>Usługobiorca akceptuje niniejszy Regulamin.</li>
<li>Usługobiorca podaje w Formularzu rejestracyjnym dane niezbędne do korzystania z Serwisu.</li>
</ol>
</li>
<li>Usługobiorca powinien wypełnić Formularz rejestracyjny w następujący sposób:
<ol>
<li>
wszystkie wymagane pola Formularza powinny być uzupełnione,
</li>
<li>
informacje wpisane do Formularza powinny dotyczyć Usługobiorcy lub osób działających w imieniu
Usługobiorcy oraz być zgodne z prawdą.
</li>
<li>
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.
</li>
</ol>
</li>
<li>
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.
</li>
<li>
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.
</li>
</ol>
<h3>§ 5. KONTO</h3>
<ol>
<li>
Użytkownikiem Konta jest osoba wskazana w Formularzu.
</li>
<li>
Z Konta może korzystać wyłącznie osoba wskazana w Formularzu.
</li>
<li>
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).
</li>
<li>
Użytkownik wskazując nazwę Użytkownika nie może podszywać się pod innych Użytkowników, Usługobiorców lub
pod Usługodawcę.
</li>
<li>
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ę.
</li>
<li>
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.
</li>
<li>
Usługodawca ma prawo zablokować Użytkownikowi Konto, gdy:
<ol>
<li>
Użytkownik wykorzystuje Konto z naruszeniem obowiązującego prawa oraz postanowień niniejszego
Regulaminu,
</li>
<li>
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.
</li>
</ol>
</li>
<li>
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.
</li>
</ol>
<h3>§ 6. KORZYSTANIE Z SERWISU</h3>
<ol>
<li>
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.
</li>
<li>
Aby uzyskać dostęp do Usług znajdujących się na Serwisie, Usługobiorca musi wypełnić Formularz oraz
zaakceptować niniejszy Regulamin.
</li>
</ol>
<h3>§ 7. KORZYSTANIE Z ZARZĄDZANIA OGŁOSZENIAMI USŁUG;</h3>
<ol>
<li>
Tworzenie, modyfikowanie i usuwanie usługi odbywa się przez utworzenie konta przedsiębiorcy oraz
wypełnienie formularza usługi.
</li>
<li>
<ol>
<li>
Konto przedsiębiorcy może zostać utworzone jedynie przez Mieszkańca i/lub Upoważnionego
użytkownika.
</li>
<li>
Utworzenie konta Upoważnionego użytkownika jest możliwe jedynie poprzez wysłanie wiadomości
e-mail na adres <a href="mailto:adrian.wozniak@ita-prog.pl">adrian.wozniak@ita-prog.pl</a> z
tytułem "Proszę o konto upoważnione" oraz opisaniem
konta w treści wiadomości.
</li>
</ol>
</li>
<li>
Usługodawca zastrzega sobie prawo do odmowy publikowania usługi bez podania przyczyny.
</li>
<li>
Usługodawca nie ponosi odpowiedzialności za zmiany w ogłoszeniach opublikowanych przez właściciela
ogłoszenia.
</li>
<li>
Wymagane jest posiadanie przez Usługobiorcę łącza dostępowego do Internetu o szybkość transmisji minimum
1024/256 kb/s.
</li>
<li>
Sprzęt komputerowy Usługobiorcy musi być wyposażony w dowolną przeglądarkę internetową.
</li>
<li>
Usługodawca nie ponosi odpowiedzialności za nieodpowiednią konfigurację sprzętu komputerowego
Usługobiorcy.
</li>
</ol>
<h3>§ 8. KORZYSTANIE Z Targu</h3>
<ol>
<li>
Usługodawca na łamach Serwisu daje możliwość Usługobiorcom do korzystania z wystawiania prywatnych
przedmiotów na sprzedaż oraz ich przeglądania.
</li>
<li>
Dodawanie ogłoszenia sprzedaży w Targu jest dostępne tylko i wyłącznie dla Mieszkańców.
</li>
<li>
Usługodawca nie ponosi odpowiedzialności za treść danych i informacji wchodzących w skład Targu.
</li>
<li>
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.
</li>
<li>Usługodawca zaleca, aby wszelkie informacje i dane zawarte raportach, prezentacjach oraz innych
dokumentach były konsultowane z właściwym doradcą.
</li>
<li>Usługodawca nie ponosi odpowiedzialności wobec Usługobiorcy za treści zawarte w raportach, prezentacjach
oraz innych dokumentach.
</li>
</ol>
<h3>§ 9. PRAWA I OBOWIĄZKI USŁUGOBIORCY</h3>
<ol>
<li>
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.
</li>
<li>
Usługobiorca zobowiązany jest do wprowadzania danych zgodnych ze stanem faktycznym i prawnym.
</li>
<li>
Usługobiorca zobowiązuje się do nieprzekazywania za pomocą Serwisu żadnych bezprawnych treści.
</li>
<li>
Usługobiorca ma obowiązek zapoznania się z treścią niniejszego Regulaminu.
</li>
<li>
Usługobiorca ma świadomość jakiej tematyki jest Serwis oraz jakiego rodzaju i zakresu Usługi są na nim
oferowane.
</li>
<li>
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.
</li>
</ol>
<h3>§ 10. OPŁATY I METODY PŁATNOŚCI</h3>
<ol>
<li>
Wskazane przez Usługodawcę funkcjonalności Serwisu mogą być odpłatne. Wysokość opłat dostępna będzie
bezpośrednio w Serwisie.
</li>
<li>
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%).
</li>
<li>
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ę.
</li>
<li>
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
<a href="mailto:adrian.wozniak@ita-prog.pl">adrian.wozniak@ita-prog.pl</a>.
</li>
<li>
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.
</li>
<li>
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.
</li>
<li>
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.
</li>
</ol>
<h3>§ 11. POSTĘPOWANIE REKLAMACYJNE</h3>
<ol>
<li>
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.
</li>
<li>
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.
</li>
<li>
W przypadku upływu powyższego terminu prawo do złożenia reklamacji przez Usługobiorcę wygasa.
</li>
<li>
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.
</li>
<li>
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.
</li>
</ol>
<h3>§ 12. PRAWA I OBOWIĄZKI USŁUGODAWCY</h3>
<ol>
<li>Usługa zostanie wykonana z należytą starannością przez Usługodawcę.</li>
<li>Odpowiedzialność Usługodawcy jest wyłączona w przypadku gdy:
<ol>
<li>
Usługobiorca i/lub Użytkownik działa bezprawnie,
</li>
<li>
Usługobiorca i/lub Użytkownik podał fałszywe dane i informacje o sobie oraz informacje służące
do wykonania Usługi.
</li>
</ol>
</li>
<li>
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:
<ol>
<li>
podania błędnych lub niepełnych danych i informacji,
</li>
<li>
podejrzenia Usługobiorcy i/lub Użytkownika o bezprawne korzystanie z Serwisu lub w sposób
niezgodny z niniejszym Regulaminem,
</li>
<li>
braku opłaty za Usługi odpłatne,
</li>
<li>
innych istotnych przyczyn uniemożliwiających świadczenie Usług przez Usługodawcę, o których
Usługobiorca zostanie poinformowany.<br> <br> 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.
</li>
</ol>
</li>
<li>
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.
</li>
<li>
Usługodawca jest uprawniony do przerw lub zakłóceń w świadczeniu Usług drogą elektroniczną i
udostępniania Serwisu, jeśli powodem jest:
<ol>
<li>
modernizacja, modyfikacja, konserwacja lub rozbudowa systemu teleinformatycznego lub
oprogramowania Usługodawcy;
</li>
<li>
działania niezależnych od Usługodawcy osób trzecich, w tym siła wyższa.
</li>
</ol>
</li>
<li>
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.
</li>
<li>
Usługodawca ma prawo w każdym czasie zamknąć Serwis i zakończyć świadczenie Usług.
</li>
</ol>
<h3>§ 13. ODPOWIEDZIALNOŚĆ USŁUGODAWCY</h3>
<ol>
<li>
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.
</li>
<li>
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ę.
</li>
<li>
Odpowiedzialność Usługodawcy wobec Usługobiorcy za Usługi bezpłatne oferowane w Serwisie jest
wyłączona.
</li>
<li>
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.
</li>
<li>
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.
</li>
<li>
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.
</li>
<li>
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.
</li>
</ol>
<h3>§ 14. POUFNOŚĆ</h3>
<ol>
<li>
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:
<ol>
<li>
są lub stały się znane opinii publicznej w inny sposób niż na skutek naruszenia postanowień
niniejszego Regulaminu,
</li>
<li>
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,
</li>
<li>
były znane odbiorcy tych informacji w momencie ich ujawnienia lub zostały później niezależnie
utworzone,
</li>
<li>
zostały ujawnione w celu wyegzekwowania praw przysługujących odbiorcy tych informacji na
podstawie niniejszej Umowy,
</li>
<li>
muszą zostać ujawnione na podstawie obowiązujących przepisów prawnych, procedur sądowych lub
regulacji zawodowych.
</li>
</ol>
</li>
<li>
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.
</li>
</ol>
<h3>§ 15. DANE OSOBOWE I COOKIES</h3>
<ol>
<li>
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.
</li>
<li>
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.
</li>
<li>
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.
</li>
<li>
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.
</li>
<li>
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 &amp; 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.
</li>
<li>
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.
</li>
<li>
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).
</li>
<li>
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.
</li>
<li>
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.
</li>
<li>
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.
</li>
<li>
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.
</li>
<li>
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ę.
</li>
<li>
Usługobiorca ma prawo wnieść skargę do organu nadzorczego w zakresie przetwarzania danych osobowych.
</li>
<li>
Kontakt do inspektora danych osobowych: kontaktdaneosoboweEYPolska@pl.ey.com.
</li>
<li>
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.
</li>
<li>
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.
</li>
<li>
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.
</li>
</ol>
<h3>§ 16. WŁASNOŚĆ INTELEKTUALNA</h3>
<ol>
<li>
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 .
</li>
<li>
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.
</li>
<li>
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.
</li>
<li>
Jakiekolwiek naruszenie powyższych praw Usługodawcy może skutkować odpowiedzialnością cywilną oraz
karną.
</li>
</ol>
<h3>§ 17. POSTANOWIENIA KOŃCOWE</h3>
<ol>
<li>
Niniejszy Regulamin obowiązuje od dnia zamieszczenia go w Serwisie Usługodawcy.
</li>
<li>
Regulamin jest dostępny w języku polskim
</li>
<li>
Regulamin jest udostępniany nieodpłatnie za pośrednictwem Serwisu.
</li>
<li>
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.
</li>
<li>
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.
</li>
<li>
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.
</li>
<li>
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ć.
</li>
<li>
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.
</li>
</ol>
</div>
</terms-and-conditions>
{% endblock %}

View File

@ -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')) {

View File

@ -27,14 +27,6 @@ customElements.define('contact-info-editor', class extends Component {
</style>
<section>
<form method="post" action="/contacts/create">
<div style="display: none">
<label>Typ</label>
<select name="contact_type" id="contact_type">
<option value="email">E-Mail</option>
<option value="facebook">Facebook</option>
<option value="other">Other</option>
</select>
</div>
<div id="contact-wrapper">
<label>E-Mail</label>
<div id="input">
@ -43,6 +35,7 @@ customElements.define('contact-info-editor', class extends Component {
</div>
<input type="text" id="content" name="content" />
<input type="hidden" id="contact_type" name="contact_type" />
</div>
</div>
<div>
@ -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';
}

View File

@ -1,7 +1,6 @@
import { Component } from "../shared";
customElements.define('contact-info',
class extends Component {
customElements.define('contact-info', class extends Component {
static get observedAttributes() {
return ['contact-type', 'content', 'contact-id', 'mode'];
}
@ -30,6 +29,19 @@ customElements.define('contact-info',
</a>
</section>
`);
this.shadowRoot.querySelector('a').addEventListener('click', ev => {
if (this.contact_type === 'mobile') {
ev.preventDefault();
const decoded = atob(this.content);
if (this.#isMobile()) {
const link = `tel:${ decoded }`;
window.open(link);
} else {
const match = decoded.match(/(\+\d+ ?)?(\d{3})([ \-])?(\d{3})([ \-])?(\d+)/);
this.shadowRoot.querySelector('section').innerHTML = `<div>${ match[2] } ${ match[4] } ${ match[6] }</div>`;
}
}
});
}
set contact_type(v) {
@ -79,11 +91,15 @@ customElements.define('contact-info',
#createLinkPath() {
const s = this.shadowRoot.querySelector('#content').textContent || '';
switch (this.contact_type) {
case 'facebook':
case 'other':
return s;
case 'email':
return `mailto:${s}`;
return `mailto:${ s }`;
default:
return s;
}
}
});
#isMobile() {
return !!navigator.userAgent.toLowerCase().match(/mobile/i);
}
});

View File

@ -20,6 +20,9 @@ customElements.define('contact-type-icon',
:host([contact-type="other"]) #other-icon {
display: block;
}
:host([contact-type="mobile"]) #mobile-icon {
display: block;
}
</style>
<svg id="email-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 75.294 75.294" xml:space="preserve">
@ -31,6 +34,15 @@ customElements.define('contact-type-icon',
<svg id="other-icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="none" stroke="#000" stroke-width="2" d="M1 2h21v16h-8l-8 4v-4H1V2Zm5 8h1v1H6v-1Zm5 0h1v1h-1v-1Zm5 0h1v1h-1v-1Z"/>
</svg>
<svg id="mobile-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 557.389 557.389" xml:space="preserve">
<path d="M368.318 0H189.061c-29.223 0-62.529 34.721-62.529 65.159V492.22c0 30.447 33.306 65.169 62.529 65.169h179.258c29.225 0 62.539-34.722 62.539-65.169V65.159C430.857 34.721 397.543 0 368.318 0zm48.196 492.229c0 23.275-26.125 50.825-48.195 50.825H189.061c-22.07 0-48.186-27.55-48.186-50.825V65.159c0-23.275 26.125-50.815 48.186-50.815h179.258c22.07 0 48.195 27.549 48.195 50.815v427.07z"/>
<path d="M289.15 477.341a1.079 1.079 0 0 0-1.49.172c-.363.469-.287 1.139.172 1.492a14.682 14.682 0 0 1 5.594 11.561c0 8.129-6.598 14.736-14.726 14.736-8.119 0-14.727-6.607-14.727-14.736 0-4.561 2.065-8.797 5.671-11.618a1.034 1.034 0 0 0 .191-1.473c-.363-.469-1.033-.564-1.492-.191a16.767 16.767 0 0 0-6.493 13.282c0 9.305 7.564 16.868 16.859 16.868 9.294 0 16.859-7.563 16.859-16.868a16.862 16.862 0 0 0-6.418-13.225z"/>
<path d="M278.69 491.627c.593 0 1.062-.469 1.062-1.062v-15.777c0-.594-.479-1.062-1.062-1.062s-1.062.468-1.062 1.062v15.777a1.06 1.06 0 0 0 1.062 1.062z"/>
<path d="M278.69 458.866c-18.063 0-32.761 14.697-32.761 32.761s14.697 32.762 32.761 32.762c18.064 0 32.761-14.698 32.761-32.762s-14.687-32.761-32.761-32.761zm0 60.741c-15.425 0-27.979-12.546-27.979-27.98 0-15.424 12.546-27.979 27.979-27.979s27.98 12.546 27.98 27.979c0 15.425-12.547 27.98-27.98 27.98zM361.053 87.927H196.347c-12.527 0-22.711 10.174-22.711 22.711v304.804c0 12.518 10.184 22.711 22.711 22.711h164.706c12.525 0 22.711-10.193 22.711-22.711V110.638c0-12.527-10.196-22.711-22.711-22.711zm15.539 327.515c0 8.568-6.973 15.539-15.539 15.539H196.347c-8.568 0-15.539-6.971-15.539-15.539V110.638c0-8.568 6.971-15.539 15.539-15.539h164.706c8.566 0 15.539 6.971 15.539 15.539v304.804z"/>
<circle cx="233.02" cy="55.769" r="5.977"/>
<circle cx="272.723" cy="55.769" r="5.977"/>
<circle cx="312.426" cy="55.769" r="5.977"/>
</svg>
`);
}

View File

@ -0,0 +1,14 @@
import { Component } from "../shared";
customElements.define('marketplace-offer', class extends Component {
constructor() {
super(`
<style>
:host {
display: block;
}
</style>
<slot></slot>
`);
}
});

View File

@ -0,0 +1,14 @@
import { Component } from "../shared";
customElements.define('marketplace-offers', class extends Component {
constructor() {
super(`
<style>
:host {
display: block;
}
</style>
<slot></slot>
`);
}
});

View File

@ -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(`
<style>
:host { display: block; }
${ FORM_STYLE }
</style>
<section>
<form action="/offers/create" method="post">
<div>
<image-input></image-input>
<input name="picture_url" id="picture_url" type="hidden" />
</div>
<div>
<label for="description">Opis</label>
<input name="description" id="description" type="text" />
</div>
<div>
<input id="submit" type="submit" value="Utwótz" />
</div>
</form>
</section>
`);
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ń';
}
});

View File

@ -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 }
</style>
<article>
<button id="accept-terms">
<h5>Zapoznałem się i zgadzam się z</h5>
<a target="_blank" href="/terms-and-condition">
Regulaminem
</a>
</button>
</article>
`);
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 = `
<ul>
<li>
<a id="user">
@ -63,8 +96,7 @@ customElements.define('register-user-type', class extends Component {
</a>
</li>
</ul>
</article>
`);
`;
const user = this.shadowRoot.querySelector('#user');
user.addEventListener('click', ev => {

View File

@ -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 }
}
})

View File

@ -0,0 +1,14 @@
import { Component } from "../shared";
customElements.define('terms-and-condition-rule', class extends Component {
constructor() {
super(`
<style>
:host {
display: block;
}
</style>
<slot></slot>
`);
}
});

View File

@ -0,0 +1,14 @@
import { Component } from "../shared";
customElements.define('terms-and-conditions', class extends Component {
constructor() {
super(`
<style>
:host {
display: block;
}
</style>
<slot></slot>
`);
}
});

View File

@ -0,0 +1,2 @@
ALTER TABLE offers
ADD COLUMN search tsvector;

View File

@ -0,0 +1,2 @@
ALTER TABLE offers
ADD COLUMN description text;

View File

@ -0,0 +1,2 @@
ALTER TABLE offers
ADD COLUMN owner_id INT REFERENCES accounts (id) NOT NULL;

View File

@ -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<String>,
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<String>,
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<String>,
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,
}

View File

@ -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)]

View File

@ -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<T> = std::result::Result<T, Error>;
@ -979,3 +988,139 @@ RETURNING id, login, email, pass, facebook_id, account_type
}
})
}
#[tracing::instrument]
pub async fn all_offers(t: &mut T<'_>) -> Result<Vec<db::Offer>> {
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<Vec<db::Offer>> {
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<Vec<db::Offer>> {
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<db::Offer> {
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<db::Offer> {
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 }
})
}

View File

@ -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);

View File

@ -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);

View File

@ -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<db::Account>,
error: Option<String>,
page: Page,
h: Helper,
offers: Vec<db::Offer>,
}
#[get("/account/offers")]
pub async fn account_offers(id: Identity, db: Data<PgPool>) -> Result<HttpResponse> {
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);
}

View File

@ -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);

View File

@ -32,10 +32,7 @@ impl AccountTemplate {
}
}
pub fn bad_request<Error: Into<String>>(
error: Error,
page: Page,
) -> routes::Result<HttpResponse> {
pub fn bad_request<Error: Into<String>>(error: Error, page: Page) -> Result<HttpResponse> {
Ok(HttpResponse::BadRequest().body(AccountTemplate::error(error, page).render().unwrap()))
}
}

View File

@ -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<String>,
page: Page,
h: Helper,
offers: Vec<db::Offer>,
}
#[get("")]
async fn marketplace() -> Result<HttpResponse> {
async fn marketplace(db: Data<PgPool>, id: Identity) -> Result<HttpResponse> {
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()

View File

@ -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<db::Account>,
error: Option<String>,
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);
}

View File

@ -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)
}
}