commit 82f8b28353e561739bd4c1d0de7ef39386611c14 Author: julien Date: Thu Oct 22 01:07:27 2026 +0200 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a591038 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.ruby-lsp/ +.env diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ce63d4d --- /dev/null +++ b/Gemfile @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +group :development do + gem "irb" + gem "dotenv" +end + +gem "roda" +gem "rackup" +gem "puma" +gem "tilt" +gem "erubi" +gem "mail" diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..95eb8f3 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,102 @@ +GEM + remote: https://rubygems.org/ + specs: + date (3.6.0) + dotenv (3.2.0) + erb (6.0.7) + erubi (1.13.1) + io-console (0.9.4) + irb (1.18.0) + pp (>= 0.6.0) + prism (>= 1.3.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + logger (1.7.0) + mail (2.9.1) + logger + mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp + mini_mime (1.1.5) + net-imap (0.6.8) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.4.0) + timeout + net-smtp (0.5.2) + net-protocol + nio4r (2.7.5) + pp (0.6.4) + prettyprint + prettyprint (0.2.1) + prism (1.9.0) + puma (8.0.2) + nio4r (~> 2.0) + rack (3.2.7) + rackup (2.3.1) + rack (>= 3) + rbs (4.2.0) + logger + prism (>= 1.6.0) + tsort + rdoc (8.1.0) + erb + prism (>= 1.6.0) + rbs (>= 4.0.0) + tsort + reline (0.7.0) + io-console (~> 0.5) + roda (3.109.0) + rack + tilt (2.9.0) + timeout (0.6.1) + tsort (0.2.0) + +PLATFORMS + ruby + x86_64-linux + +DEPENDENCIES + dotenv + erubi + irb + mail + puma + rackup + roda + tilt + +CHECKSUMS + date (3.6.0) sha256=18ac945c4e24ebd93534f8eab8c2fd8c5604b3e977105b3798d62a1e8d27b580 + dotenv (3.2.0) sha256=e375b83121ea7ca4ce20f214740076129ab8514cd81378161f11c03853fe619d + erb (6.0.7) sha256=c5ca6dc25b0ef974a44dc8f59fe847577122483b1968a38dec305c60bf91ee92 + erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9 + io-console (0.9.4) sha256=a403304f32928ee85e56d457b4612ca43f2703b561a3258844992bd24085fbb1 + irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3 + logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203 + mail (2.9.1) sha256=06574eca475253d6c18145dd70af80d0eb970182d55053497c5f4d797ea160e8 + mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef + net-imap (0.6.8) sha256=eb30bb62227b64a3af6b518b04b2375113d69f68f15de59b0193b07d98acf6d9 + net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3 + net-protocol (0.4.0) sha256=f9f90c8c6f64794a45160bf422177a336db12809de3beeeaa26b88fcd2e8c853 + net-smtp (0.5.2) sha256=35103cc04d6b2d94632f9928ede07483c24b70b9c0db1f231fea43909b678f3c + nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1 + pp (0.6.4) sha256=dfcb0fce700c41456265922884f9fe195d7fbb0674a3578e6c0f69588e82b570 + prettyprint (0.2.1) sha256=d555d57ea6d7cf001d4774b693546a6bd88bec1e778ddffb5c60b68ceec4b7d4 + prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85 + puma (8.0.2) sha256=c8ed871dfbbe66448ea9ffd46692342d9804d4071522b52b5331b7b6e7b686fb + rack (3.2.7) sha256=93e13e1c24f93556671d85d2d79fa228c3485815c50d7e2f265b5330c6528fb7 + rackup (2.3.1) sha256=6c79c26753778e90983761d677a48937ee3192b3ffef6bc963c0950f94688868 + rbs (4.2.0) sha256=51f7b886dcc05bc09e10b901daa6a81829f6adc03101d6ca9ea4aac6103e0674 + rdoc (8.1.0) sha256=befc37880a5cfd36dcb176c748b5fd5ee39dd3536a75e81824e4972ce230f60a + reline (0.7.0) sha256=5b012d8e55dbf9d450f12bde2cf7d15ff546ae80b3f8f3b30e570d431815583d + roda (3.109.0) sha256=470f60355043a7732edb08ece2d12eb2e6912866ac87106c92ded5f6f8a5a8dc + tilt (2.9.0) sha256=da5735d0280bba96e9a91041bb14aee435ccad5c17b0fa519249ae543d9aa3a5 + timeout (0.6.1) sha256=78f57368a7e7bbadec56971f78a3f5ecbcfb59b7fcbb0a3ed6ddc08a5094accb + tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f + +BUNDLED WITH + 4.0.20 diff --git a/README.md b/README.md new file mode 100644 index 0000000..22f4a16 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# netig.net + +## Développement + +Installer les dépendances : + +```sh +bundle install +``` + +Créer un fichier `.env` à la racine du projet : + +```dotenv +SESSION_SECRET=... +SMTP_PASSWORD=... +``` + +Générer `SESSION_SECRET` avec `openssl rand -hex 64` et conserver la valeur dans `.env`. + +Démarrer le serveur de développement : + +```sh +bundle exec rackup +``` + +Ou ouvrir un shell interactif : + +```sh +bundle exec irb -r dotenv/load -r ./netig.rb +``` + +## Production + +Docker Compose fournit les variables avec `env_file` et définit `RACK_ENV=production`. diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..8f4780a --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require "dotenv/load" if ENV.fetch("RACK_ENV", "development") == "development" +require_relative "netig" + +run Netig.freeze.app diff --git a/config/mail.rb b/config/mail.rb new file mode 100644 index 0000000..cc2968b --- /dev/null +++ b/config/mail.rb @@ -0,0 +1,13 @@ +require "mail" + +Mail.defaults do + delivery_method :smtp, { + :address => "mail.netig.net", + :port => 587, + :domain => "netig.net", + :user_name => "noreply@netig.net", + :password => ENV.fetch("SMTP_PASSWORD"), + :authentication => "plain", + :enable_starttls => :always + } +end diff --git a/lib/contact_form.rb b/lib/contact_form.rb new file mode 100644 index 0000000..917a4ab --- /dev/null +++ b/lib/contact_form.rb @@ -0,0 +1,36 @@ +class ContactForm + LIMITS = { + "email" => 254, + "name" => 128, + "subject" => 200, + "message" => 5000 + }.freeze + + def initialize(params) + @params = params + end + + def spam? + !@params["website"].to_s.empty? + end + + def valid? + fields_valid = LIMITS.all? do |key, max| + value = @params[key] + + value.is_a?(String) && + value.valid_encoding? && + !value.strip.empty? && + value.strip.length <= max + end + + return false unless fields_valid + + email_valid = @params["email"].strip.match?(/\A[^\s@]+@[^\s@]+\.[^\s@]+\z/) + headers_valid = %w[name subject].none? do |key| + @params[key].match?(/[\r\n]/) + end + + email_valid && headers_valid + end +end diff --git a/lib/contact_mailer.rb b/lib/contact_mailer.rb new file mode 100644 index 0000000..24908c3 --- /dev/null +++ b/lib/contact_mailer.rb @@ -0,0 +1,27 @@ +require "mail" + +class ContactMailer + def initialize(params) + @params = params + end + + def build + email = @params["email"] + name = @params["name"] + subject = @params["subject"] + message = @params["message"] + + Mail.new do + from "noreply@netig.net" + to "contact@netig.net" + reply_to email + content_type "text/plain; charset=UTF-8" + subject subject + body "Nom : #{name}\n\n#{message}" + end + end + + def deliver + build.deliver + end +end diff --git a/netig.rb b/netig.rb new file mode 100644 index 0000000..8c3e4ab --- /dev/null +++ b/netig.rb @@ -0,0 +1,35 @@ +require "roda" + +require_relative "config/mail" +require_relative "lib/contact_form" +require_relative "lib/contact_mailer" + +class Netig < Roda + plugin :render, escape: true + plugin :public + plugin :default_headers, "Content-Type" => "text/html; charset=utf-8" + plugin :sessions, secret: ENV.fetch("SESSION_SECRET") + plugin :route_csrf + plugin :hash_branches + plugin :flash + + require_relative "routes/contact" + + route do |r| + r.public + r.hash_branches + + r.root do + @canonical_url = "https://netig.net/" + view "index" + end + + r.get "legal" do + @page_title = "Mentions légales — NETig" + @page_description = "Mentions légales de l'association NETig." + @canonical_url = "https://netig.net/legal" + + view "legal" + end + end +end diff --git a/public/css/style.css b/public/css/style.css new file mode 100644 index 0000000..cc51b2e --- /dev/null +++ b/public/css/style.css @@ -0,0 +1,551 @@ +/* Polices +------------------------------------------------------------------------ */ + +@font-face { + font-family: "TitilliumWeb"; + src: url("/fonts/TitilliumWeb-Regular.woff2") format("woff2"); + font-weight: 400; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "TitilliumWeb"; + src: url("/fonts/TitilliumWeb-Bold.woff2") format("woff2"); + font-weight: 700; + font-style: normal; + font-display: swap; +} + +/* Couleurs +------------------------------------------------------------------------ */ + +:root { + /* Fonds */ + --color-background: #2f3e46; + --color-surface: #354f52; + --color-surface-dark: #243138; + + /* Texte et accents */ + --color-text: #cad2c5; + --color-link: #a9cecf; + --color-accent: #a8c9a5; + --color-highlight: #ebdbb2; + --color-heading-soft: #c7d9c9; + + /* Messages */ + --color-flash-notice-background: #294e43; + --color-flash-error-background: #2c4647; + --color-flash-error-border: #e6afa2; + + /* Ombres */ + --color-shadow-light: rgb(202 210 197 / 20%); + --color-shadow-dark: rgb(0 0 0 / 8%); +} + +/* Structure et mise en page +------------------------------------------------------------------------ */ + +*, +*::before, +*::after { + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; +} + +body { + display: flex; + flex-direction: column; + min-height: 100vh; + min-height: 100dvh; + margin: 0; + background: var(--color-background); + color: var(--color-text); + font-family: "TitilliumWeb", sans-serif; + font-size: 1.4rem; +} + +main { + display: flex; + flex: 1; + min-width: 0; + flex-direction: column; +} + +/* Image sur les sections alternées de l'accueil et les pages intérieures. */ +main > section { + background-color: var(--color-background); +} + +main > section:nth-of-type(odd):not(:only-of-type), +.page-section { + background-color: var(--color-surface); + background-image: + linear-gradient(rgb(15 40 55 / 74%), rgb(15 40 55 / 74%)), + url("/images/background.webp"); + background-position: center; + background-size: cover; + background-repeat: no-repeat; +} + +.content { + width: 100%; + max-width: 1200px; + margin-inline: auto; + padding: 20px; +} + +.prose { + max-width: 72ch; + line-height: 1.6; +} + +/* Une seule feuille de lecture sur les pages intérieures. */ +.page-section { + flex: 1; + padding: clamp(24px, 5vw, 72px) 20px; +} + +.page-panel { + max-width: 1000px; + padding: clamp(24px, 4vw, 48px); + border-radius: 16px; + background: var(--color-background); +} + +.page-panel.prose { + max-width: 72ch; +} + +.section-services, +.section-hosting { + padding-bottom: 100px; +} + +/* Typographie et liens +------------------------------------------------------------------------ */ + +h1, +h2, +h3, +h4 { + color: var(--color-text); + font-weight: 700; + text-align: left; +} + +h1 { + margin-block: 0.67em; + font-size: 2.8rem; + line-height: 1.1; +} + +h2 { + padding-left: 14px; + border-left: 4px solid var(--color-highlight); + color: var(--color-highlight); + font-size: 2.6rem; + line-height: 1.15; +} + +h3 { + width: fit-content; + padding-bottom: 0.25rem; + border-bottom: 2px solid var(--color-accent); + color: var(--color-highlight); + font-size: 1.9rem; + line-height: 1.2; +} + +h4 { + color: var(--color-heading-soft); + font-size: 1.4rem; + line-height: 1.25; +} + +a { + color: var(--color-link); + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +a:focus-visible, +button:focus-visible, +input:focus-visible, +textarea:focus-visible, +select:focus-visible, +summary:focus-visible { + outline: 3px solid var(--color-accent); + outline-offset: 3px; +} + +.skip-link { + position: fixed; + top: 10px; + left: 10px; + z-index: 100; + padding: 8px 12px; + background: var(--color-text); + color: var(--color-background); + transform: translateY(-200%); +} + +.skip-link:focus { + transform: translateY(0); +} + +/* En-tête et navigation +------------------------------------------------------------------------ */ + +.topbar { + display: flex; + min-height: 70px; + flex-wrap: wrap; + align-items: center; + text-align: left; + background: var(--color-surface); + border-bottom: 1px solid rgb(202 210 197 / 18%); +} + +.topbar a { + padding-left: 20px; +} + +.topbar a:hover { + color: var(--color-text); +} + +.topbar a.topbar__account { + margin-left: auto; + margin-right: 20px; + padding: 8px 14px; + border: 1px solid var(--color-accent); + color: var(--color-accent); +} + +.topbar a.topbar__account:hover { + background: var(--color-accent); + color: var(--color-background); + text-decoration: none; +} + +.topbar img { + display: block; + width: 48px; + height: 48px; +} + +.logo { + display: flex; + align-items: center; + justify-content: center; +} + +.logo img { + display: block; + width: 100%; + max-width: 340px; + height: auto; +} + +.hero p { + font-size: 1.6rem; +} + +.hero h1 { + font-size: clamp(2.8rem, 6vw, 4rem); +} + +.hero__lead { + margin-bottom: 0; +} + +.hero__actions { + display: flex; + flex-wrap: wrap; + gap: 12px; + margin-top: 28px; +} + +/* Boutons et cartes +------------------------------------------------------------------------ */ + +.button { + display: inline-block; + padding: 10px 16px; + border: 2px solid var(--color-accent); + background: var(--color-accent); + color: var(--color-background); + font-weight: 700; + transition: filter 0.2s ease; +} + +.button:hover { + filter: brightness(1.12); + text-decoration: none; +} + +.button--secondary { + display: inline-flex; + align-items: center; + gap: 8px; + border-color: var(--color-link); + background: transparent; + color: var(--color-link); +} + +.box { + display: flex; + min-width: 0; + flex-direction: column; + justify-content: space-between; + margin-top: 80px; + padding: 20px 20px 40px; + border: 2px solid var(--color-text); + box-shadow: 0 0 5px var(--color-shadow-light), 0 4px 4px var(--color-shadow-dark); +} + +.box img { + display: block; + max-width: 96px; + margin-inline: auto; +} + +.box__title { + margin-block: 0; + padding: 10px; + border-bottom: 0; + background: var(--color-background); + color: var(--color-text); + translate: 0 -55px; +} + +/* Bordure supérieure interrompue autour des titres, sans masquer la photo. */ +.section-hosting .box { + border-top: 0; + background: rgb(15 40 55 / 30%); +} + +.section-hosting .box__title { + display: flex; + align-items: center; + gap: 8px; + width: auto; + margin-inline: -22px; + padding: 10px 0; + background: transparent; + translate: 0 calc(-50% - 20px); +} + +.section-hosting .box__title::before, +.section-hosting .box__title::after { + content: ""; + flex: 1; + border-top: 2px solid var(--color-text); +} + +.section-hosting .box__title::before { + flex: 0 0 20px; +} + +.box__link { + padding: 20px; + color: var(--color-text); + text-align: center; + transition: transform 0.2s ease, border-color 0.2s ease; +} + +.box__link:hover { + text-decoration: none; +} + +.service-icon { + margin-top: -20px; + margin-bottom: 10px; +} + +/* Couleur des cartes selon leur position. */ +.section-services .box:nth-child(3n + 1) { + --service-accent: var(--color-link); +} + +.section-services .box:nth-child(3n + 2) { + --service-accent: var(--color-accent); +} + +.section-services .box:nth-child(3n + 3) { + --service-accent: var(--color-highlight); +} + +.section-services .box__title { + color: var(--service-accent); +} + +.section-services .box__link:focus-visible { + border-color: var(--service-accent); +} + +/* Formulaires et messages +------------------------------------------------------------------------ */ + +.contact-form { + display: grid; + gap: 10px; + font-size: 1rem; + font-weight: 700; +} + +.contact-form input, +.contact-form textarea { + width: 100%; + margin: 0; + padding: 10px; + border: 0; + font-family: inherit; + font-size: 1rem; +} + +/* Ne pas appliquer le fond clair au bouton d'envoi. */ +.contact-form input:not([type="submit"]), +.contact-form textarea { + background: var(--color-text); + color: var(--color-background); +} + +.contact-form textarea { + min-height: 150px; + resize: vertical; + box-shadow: 0 0 10px var(--color-surface-dark); +} + +.contact-form input:not([type="submit"]):focus-visible, +.contact-form textarea:focus-visible { + outline-color: var(--color-surface); +} + +.submit { + width: 100%; + background: var(--color-accent); + color: var(--color-background); + font-weight: 700; + cursor: pointer; +} + +.honeypot { + position: absolute; + left: -10000px; + width: 1px; + height: 1px; + overflow: hidden; +} + +.flash { + margin: 0 0 1rem; + padding: 0.75rem 1rem; + border-left: 3px solid; +} + +.flash--notice { + background-color: var(--color-flash-notice-background); + border-color: var(--color-accent); + color: var(--color-text); +} + +.flash--error { + background-color: var(--color-flash-error-background); + border-color: var(--color-flash-error-border); + color: var(--color-text); +} + +/* Pied de page +------------------------------------------------------------------------ */ + +footer { + padding: 40px 20px; + background: var(--color-surface-dark); + box-shadow: 0 0 20px var(--color-surface-dark); +} + +.botbar { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + font-size: 1rem; + text-align: center; +} + +.botbar p { + margin-inline: auto; +} + +/* Adaptations et accessibilité +------------------------------------------------------------------------ */ + +@media screen and (min-width: 1080px) { + .col--1-1, + .col--1-2, + .col--1-1-1 { + display: grid; + gap: 40px; + } + + .col--1-1 { + grid-template-columns: repeat(2, 1fr); + } + + .col--1-2 { + grid-template-columns: 1fr 2fr; + } + + .col--1-1-1 { + grid-template-columns: repeat(3, 1fr); + } +} + +/* Effets au survol sur les écrans et périphériques adaptés. */ +@media (hover: hover) and (min-width: 1080px) { + .box__link:hover { + transform: scale(1.04); + } + + .section-services .box__link:hover { + border-color: var(--service-accent); + } +} + +@media screen and (max-width: 600px) { + .box { + margin-top: 60px; + padding: 20px; + } + + .section-services, + .section-hosting { + padding-bottom: 60px; + } + + footer { + padding: 24px 20px; + } +} + +@media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } + + .box__link, + .button { + transition: none; + } + + .box__link:hover { + transform: none; + } +} diff --git a/public/fonts/TitilliumWeb-Bold.woff2 b/public/fonts/TitilliumWeb-Bold.woff2 new file mode 100644 index 0000000..c34f134 Binary files /dev/null and b/public/fonts/TitilliumWeb-Bold.woff2 differ diff --git a/public/fonts/TitilliumWeb-Regular.woff2 b/public/fonts/TitilliumWeb-Regular.woff2 new file mode 100644 index 0000000..82b27bc Binary files /dev/null and b/public/fonts/TitilliumWeb-Regular.woff2 differ diff --git a/public/images/background.webp b/public/images/background.webp new file mode 100644 index 0000000..0143804 Binary files /dev/null and b/public/images/background.webp differ diff --git a/public/images/calc.svg b/public/images/calc.svg new file mode 100644 index 0000000..00b8079 --- /dev/null +++ b/public/images/calc.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/images/cloud.svg b/public/images/cloud.svg new file mode 100644 index 0000000..396e941 --- /dev/null +++ b/public/images/cloud.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/drop.svg b/public/images/drop.svg new file mode 100644 index 0000000..ce5007a --- /dev/null +++ b/public/images/drop.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/favicon.svg b/public/images/favicon.svg new file mode 100644 index 0000000..0b9a842 --- /dev/null +++ b/public/images/favicon.svg @@ -0,0 +1,37 @@ + + + + + + + + + + diff --git a/public/images/git.svg b/public/images/git.svg new file mode 100644 index 0000000..39d2b21 --- /dev/null +++ b/public/images/git.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/list.svg b/public/images/list.svg new file mode 100644 index 0000000..ccf7ae6 --- /dev/null +++ b/public/images/list.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/public/images/mail.svg b/public/images/mail.svg new file mode 100644 index 0000000..098781a --- /dev/null +++ b/public/images/mail.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/other.svg b/public/images/other.svg new file mode 100644 index 0000000..e9e008c --- /dev/null +++ b/public/images/other.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/images/pad.svg b/public/images/pad.svg new file mode 100644 index 0000000..baa94f1 --- /dev/null +++ b/public/images/pad.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/status.svg b/public/images/status.svg new file mode 100644 index 0000000..f544d11 --- /dev/null +++ b/public/images/status.svg @@ -0,0 +1,4 @@ + + + + diff --git a/routes/contact.rb b/routes/contact.rb new file mode 100644 index 0000000..dd71b3d --- /dev/null +++ b/routes/contact.rb @@ -0,0 +1,37 @@ +class Netig + hash_branch "contact" do |r| + r.is do + r.get do + @page_title = "Contact — NETig" + @page_description = "Contacter NETig pour toute question concernant ses services." + @canonical_url = "https://netig.net/contact" + + view "contact" + end + end + + r.post "send" do + check_csrf! + + form = ContactForm.new(r.params) + + if form.spam? + flash["notice"] = "Votre message a été reçu." + r.redirect "/contact" + elsif form.valid? + begin + ContactMailer.new(r.params).deliver + flash["notice"] = "Votre message a été envoyé." + rescue Net::SMTPError, SocketError, SystemCallError, IOError, Timeout::Error, OpenSSL::SSL::SSLError => error + warn "Échec SMTP : #{error.class}" + flash["error"] = "L'envoi a échoué. Veuillez réessayer plus tard." + end + r.redirect "/contact" + else + response.status = 422 + flash.now["error"] = "Veuillez vérifier les champs du formulaire." + view "contact" + end + end + end +end diff --git a/views/contact.erb b/views/contact.erb new file mode 100644 index 0000000..594fe58 --- /dev/null +++ b/views/contact.erb @@ -0,0 +1,42 @@ +
+
+

Contact

+
+
+

Vous avez un projet en tête ? Un service vous intéresse ? Ou simplement une question ? Ce formulaire est là pour ça !

+
+
+ <% if notice = flash["notice"] %> +

<%= notice %>

+ <% end %> + + <% if error = flash["error"] %> + + <% end %> + +
+ <%== csrf_tag("/contact/send") %> + + + + + + + + + + + + + + + + +
+
+
+
+
diff --git a/views/index.erb b/views/index.erb new file mode 100644 index 0000000..21af73a --- /dev/null +++ b/views/index.erb @@ -0,0 +1,119 @@ +
+
+ +
+

NETig

+

Fournisseur associatif de services numériques libres, simples et indépendants, respectueux de la vie privée, à destination des particuliers, des associations et des petites entreprises.

+ +
+
+
+ +
+ +
+ +
+
+

Services réservés aux adhérents

+

L'adhésion à NETig est gratuite ! Créez votre compte pour demander à rejoindre l'association et profiter de ses services.

+
+
+

NETmail — Adresse mail

+
+
+ +
+
+

Obtenez une adresse e-mail @netig.net ou utilisez votre propre nom de domaine. Consultez vos messages depuis un navigateur ou votre logiciel de messagerie habituel.

+
+
+
+
+

NETcloud — Fichiers en ligne

+
+
+ +
+
+

Conservez vos fichiers, photos et agendas en ligne et retrouvez-les depuis vos différents appareils. Une suite bureautique est également disponible.

+
+
+
+
+
+

NETlist — Listes de diffusion

+
+
+ +
+
+

Créez des listes pour envoyer des actualités, des annonces ou des lettres d'information à vos abonnés. Proposez des formulaires d'inscription et des archives publiques, et utilisez une adresse @netig.net ou votre propre domaine pour vos envois.

+
+
+
+
+
+

NETgit — Hébergement de code

+
+
+ +
+
+

Un espace pour conserver, partager et gérer vos projets.

+
+
+
+
+

Autre

+
+
+ +
+
+

Vous recherchez un service qui n'est pas présenté ici ? Contactez-nous pour en discuter !

+
+
+
+
+

+ Les services NETig reposent sur des logiciels libres. + Découvrez les logiciels utilisés ➜ +

+
+
+ +
+
+

Aidez-nous à continuer !

+

L'adhésion est gratuite et les services sont financés grâce aux dons. Votre soutien nous aide à couvrir les frais d'hébergement et à maintenir les services accessibles.

+ Faire un don ➜ +
+
diff --git a/views/layout.erb b/views/layout.erb new file mode 100644 index 0000000..3dafbb7 --- /dev/null +++ b/views/layout.erb @@ -0,0 +1,62 @@ + + + + + + + + + <% title = @page_title || "NETig" %> + <% description = @page_description || "Services numériques libres, simples et indépendants, pour particuliers, associations et petites structures." %> + + <%= title %> + + + + + + + + + <% if @canonical_url %> + + + <% end %> + + + + + + + + +
+ +
+ +
+ <%== yield %> +
+ + + + + + + diff --git a/views/legal.erb b/views/legal.erb new file mode 100644 index 0000000..aecf0cb --- /dev/null +++ b/views/legal.erb @@ -0,0 +1,59 @@ +
+
+

Mentions légales

+

+ NETig — Association loi 1901
+ Membres fondateurs : Julien Debrousse et John Doe
+ Siège social : [adresse]
+ RNA : [numéro]
+ Directeur de la publication : [nom] +

+ +

Contact

+

Il est possible de prendre contact par courriel à : contact@netig.net.

+ +

Hébergement des données

+

Les services sont hébergés sur des infrastructures administrées bénévolement par l'association chez Hetzner. Le VPS principal fonctionne sous Debian. Des sauvegardes quotidiennes sont conservées sur une Storage Box Hetzner située en Finlande.

+

Hébergeur : Hetzner Online GmbH — [adresse et téléphone à compléter].

+ +

Conditions générales d'utilisation

+ +

Disponibilité

+

Malgré les efforts faits pour assurer la meilleure disponibilité possible, un accès permanent aux services n'est pas garanti. Vous pouvez consulter l'état des services en temps réel depuis un outil de surveillance mis à disposition. Vous pouvez aussi vous inscrire à la liste de diffusion de maintenance, afin d'être informé des interruptions de service.

+ +

Responsabilité

+

Vous êtes responsable des contenus diffusés et êtes tenu de respecter la législation en vigueur. Le non-respect des conditions d'utilisation ou des lois en vigueur peut entraîner une suspension des services ou une suppression des données et comptes concernés.

+ +

Données personnelles

+ +

Confidentialité

+

Les données ne sont ni vendues ni utilisées à des fins publicitaires. Elles sont traitées uniquement pour gérer les adhésions, fournir, administrer et sécuriser les services, sous réserve des obligations légales applicables.

+ +

Conservation

+

Les données personnelles sont conservées pendant la durée nécessaire à la gestion des adhésions et à la mise à disposition des services, sous réserve des obligations légales de conservation. Elles peuvent persister pendant la durée de rétention des sauvegardes après la clôture des services.

+ +

Récupération

+

Vous pouvez à tout moment récupérer vos données personnelles, soit à l'aide d'une fonctionnalité intégrée à un service, soit sur demande.

+ +

Suppression

+

Vous pouvez demander la suppression de vos données personnelles, soit à l'aide d'une fonctionnalité intégrée à un service, soit sur demande écrite, sous réserve des obligations légales de conservation.

+ +

Vos droits

+

Vous pouvez exercer vos droits d'accès, de rectification, d'effacement et les autres droits prévus par la réglementation applicable en écrivant à contact@netig.net. Vous pouvez également introduire une réclamation auprès de la CNIL.

+ +

Services en libre accès

+

Ces services sont accessibles à tous afin de proposer une alternative aux produits des GAFAM ou « Géants du web », respectueuse des données de chacun. Les ressources matérielles ne sont pas sans limites : utilisez-les avec bon sens. En cas d'abus et après un premier avertissement lorsque cela est possible, votre adresse IP pourra être bannie.

+ +

Services réservés aux adhérents

+ +

Adhésion

+

L'adhésion à l'association est gratuite et soumise à validation conformément à ses statuts. Elle permet de demander l'accès aux services réservés aux adhérents, dans la limite des ressources disponibles. L'adhésion ne garantit pas l'attribution automatique d'un service.

+ +

Dons

+

L'association est financée par des dons libres et volontaires destinés à couvrir ses frais de fonctionnement. Aucun don n'est obligatoire pour adhérer ou bénéficier des services. Les dons ne donnent droit à aucun accès ou avantage supplémentaire.

+ +

Suspension et résiliation

+

Le non-respect des conditions d'utilisation peut entraîner une suspension ou une suppression des services concernés, notamment en cas d'abus. Vous pouvez à tout moment demander la désactivation d'un service et la suppression des données associées, sous réserve des obligations légales de conservation.

+
+
+