No description
  • Go 95.6%
  • Go Template 2.7%
  • CSS 0.9%
  • Dockerfile 0.4%
  • HTML 0.4%
Find a file
fedoryuk_au 7c2c22353f
All checks were successful
ci/woodpecker/tag/woodpecker Pipeline was successful
fix: CI
2026-07-10 10:07:38 +03:00
.vscode fix: Нормализация в webhook поля data, удаление selected и checked 2026-07-10 09:47:37 +03:00
cmd fix: Нормализация в webhook поля data, удаление selected и checked 2026-07-10 09:47:37 +03:00
db feat: Тесты 2026-07-09 15:51:15 +03:00
forms/test fix: Нормализация в webhook поля data, удаление selected и checked 2026-07-10 09:47:37 +03:00
http Корректировка отправки электронной почты 2024-02-06 16:31:45 +03:00
lib fix: Нормализация в webhook поля data, удаление selected и checked 2026-07-10 09:47:37 +03:00
log feat:Тесты 2026-07-09 15:08:42 +03:00
middleware feat: Тесты 2026-07-09 15:51:15 +03:00
route fix: Нормализация в webhook поля data, удаление selected и checked 2026-07-10 09:47:37 +03:00
structs fix: Нормализация в webhook поля data, удаление selected и checked 2026-07-10 09:47:37 +03:00
tmpl fix: Нормализация в webhook поля data, удаление selected и checked 2026-07-10 09:47:37 +03:00
.dockerignore Woodpecker CI/CD 2025-06-05 16:44:11 +03:00
.gitignore fix: Нормализация в webhook поля data, удаление selected и checked 2026-07-10 09:47:37 +03:00
.golangci.yml feat:Тесты 2026-07-09 15:08:42 +03:00
.woodpecker.yml fix: CI 2026-07-10 10:07:38 +03:00
coverage.out feat:Тесты 2026-07-09 15:08:42 +03:00
Dockerfile fix: CI 2026-07-10 10:07:38 +03:00
Dockerfile.amd64 fix: Устранение критичных ошибок 2026-07-09 14:53:50 +03:00
go.mod refactor: Использование go-simple-args 2026-07-09 15:56:12 +03:00
go.sum refactor: Использование go-simple-args 2026-07-09 15:56:12 +03:00
README.md fix: Нормализация в webhook поля data, удаление selected и checked 2026-07-10 09:47:37 +03:00
ROADMAP.md fix: Нормализация в webhook поля data, удаление selected и checked 2026-07-10 09:47:37 +03:00
TODO Определение списка TODO 2024-04-08 12:38:57 +03:00

Генератор регистрационных форм на различные мероприятия

Приложение предназначено для создание шаблонов форм регистрации на различные мероприятия (конференции, семинары, собрания и т.д.). Приложение перебирает директории из указанной. Каждая директория является отдельной самостоятельной формой и из нее ищет файл settings.json/settings.yaml/settings.yml.

Файл настроек

{
	"cssFiles":["Файлы со стилями"],
	"cssExternals":["Урлы для внешних файлов со стилями"],
	"jsFiles":["Файлы со скриптами"],
	"jsExternals":["Урлы для внешних скриптов"],
	"formTempl":"Шаблон формы",
	"mailTempl": "Шаблон почтового сообщения",
	"formSuccessTempl":"Шаблон формы для отображения в случае успеха",
	"title":"Заголовок формы",
	"fields":[
        {
            "name":"Название поля для БД. Он же id для html-элемента",
            "class":"Класс, который будет присвоен полю с элементом",
            "display":"Отображаемое название поля",
            "description":"Описание поля",
            "required":"Поле обязательное к заполнению",
            "type":"Тип поля",
			"multi":"Указывается true, если поле имеет несколько значений. Применяется для file и select",
			"same":"Указывается true, если помимо присутствующих значений можно выбрать 'свой вариант'",
            "select":"Варианты для поля select. Если указан параметр multi=true, то можно выбрать сразу несколько вариантов",
            "selected":"Параметр, который введен по умолчанию при открытии формы",
            "checked":"Если поле является чекбоксом то нужно ли чтобы чекбокс был установлен по умолчанию",
            "value":"Начальное значение поля",
			"regexp":"Регулярное выражение для проверки корректности ввода значения. Если пусто, то не используется",
			"format":"Фиксированный формат. На основе формата формируется регулярное выражение, которое проверяет корректность заполнения поля.",
        }
    ],
	"hasCaptcha":"Делать проверку капчи",
	"hasAcceptPersonalData":"Галочка для согласия на обработку персональных данных",
	"acceptReceiveNewsletter":"Галочка на согласие получать рассылку",
	"hasEmail":"Электронная почта для обратной связи",
	"smtpAddr":"Адрес сервера электронной почты для отправки",
	"smtpPort":"Порт сервера электронной почты для отправки",
	"smtpLogin":"Логин для отправки",
	"smtpPassword":"Пароль для отправки",
	"smtpEmailFrom":"Адрес электронной почта для отправки \"откуда\"",
	"smtpEmailTo":"Адрес электронной почта для отправки \"куда\"",
	"adminLogin":"Логин администратора формы",
	"adminPassword":"Пароль администратора формы"
}

Тип поля указывается в числовом значении:

1 - Текстовое поле

2 - Поле перечисления (select)

3 - Поле выбора файла

4 - Поле с "галочкой"

5 - Поле электронной почты (E-Mail)

6 - Телефон. Нормализация телефонного номера для сохранения в БД. В другом случае нормализованный номер телефона. Поле принимает одно значение=один номер. При нормализации удаляются все символы, кроме знака "+" в начале строки.

Шаблон

Для написания шаблона используется шаблонизатор golang text/template. Для подробной информации рекомендуется обратиться к их документации.

Важно: В каждом шаблоне формы обязательно должен присутствовать {{ csrfField $ }} внутри тега <form>. Без него POST-запросы будут отклоняться с ошибкой 403 (CSRF-защита). Подробнее — в описании функции csrfField.

Пример шаблона

<html>
<head>
<title>{{ .Title }}</title>
{{ range $index, $cssName := .CSSExternals }}
{{ externalCss $cssName }}
{{ end }}
{{ range $index, $cssName := .CSSFiles }}
{{ linkCss $ $cssName }}
{{ end }}
</head>
<body>

{{ range $index, $jsName := .JSExternals }}
{{ externalJs $jsName }}
{{ end }}
{{ range $index, $jsName := .JSFiles }}
{{ linkJs $ $jsName }}
{{ end }}

{{ $lnk := linkForm . }}
<div class="header">
<img src="{{ $lnk }}/logo.webp">
<p>{{ .Title }}</p>
</div>

<form id="register" action="{{ normalizePath $lnk }}" method="POST" enctype="multipart/form-data">
{{ csrfField $ }}
{{ range $index, $field := .Fields }}
<div class="{{ $field.Class }}">
<label for="{{ $field.Name }}">{{ $field.Display }}{{ if $field.Required }}<span class="required">*</span>{{ end }}</label>
{{ input $field }}
<div id="{{ $field.Name }}" class="error">{{ $field.Error }}</div>
</div>
{{ end }}

<div class="catpcha">
<div>
<label for="captcha">Введите текст с картинки<span class="required">*</span>{{ imageCaptcha }}</label>
</div>
{{ inputCaptcha }}
</div>

<div class="error">{{ $.Error }}</div>

<input type="submit" class="btn btn-submit" value="Отправить">
</form>
</body>
</html>

Такой же тип шаблонизации используется для вывода страницы с успешной проверкой формы и для отправки информационного сообщения. Исключение составляет то, что текст, полученный для электронной почты, используется как обычный текст, а не как HTML.

Уведомления по электронно почте

В случае успеха отправки формы отправляется электронное письмо на адрес, указанный в smtpEmailTo и, если указана опция hasEmail, то автоматически добавляется поле email как обязательное и отправляется письмо человеку, который заполняет эту форму. Различия в письмах в том, что для пользователя вложения в письмо не прикрепляются, а при отправки на smtpEmailTo - прикрепляются.

Webhook — уведомления по HTTP

В дополнение (или вместо) к уведомлениям по SMTP, приложение умеет отправлять HTTP-запросы (webhooks) при успешной отправке формы. Это позволяет интегрироваться с внешними сервисами: CRM, Telegram-боты, очереди сообщений, собственные микросервисы и т.д.

Webhook-запросы выполняются после сохранения данных в БД. Ошибки отправки только логируются — ответ пользователю не прерывается (fire-and-forget).

Настройка в settings.json

{
  "webhooks": [
    {
      "url": "https://hooks.example.com/notify",
      "method": "POST",
      "headers": {
        "X-API-Key": "abc123"
      },
      "timeoutSeconds": 10
    },
    {
      "url": "https://crm.example.com/api/lead"
    }
  ]
}

Параметры webhook

Поле Тип По умолчанию Описание
url string Обязательный. Адрес, на который будет отправлен запрос.
method string "POST" HTTP-метод. Рекомендуется оставлять POST.
headers object {} Дополнительные HTTP-заголовки (например, для аутентификации).
timeoutSeconds int 10 Таймаут ожидания ответа от сервера (в секундах).

Если массив webhooks пустой или отсутствует — webhook-запросы не выполняются.

Формат payload

В теле каждого webhook-запроса передаётся JSON следующей структуры:

{
  "form_name": "test",
  "form_title": "Тестовая форма",
  "submitted_at": "2026-07-09T12:00:00+03:00",
  "fields": [
    {
      "name": "name",
      "display": "Имя",
      "type": 1,
      "value": "Иванов Иван",
      "required": true
    },
    {
      "name": "resume",
      "display": "Резюме",
      "type": 3,
      "value": "resume.pdf",
      "required": true,
      "data": "data:application/pdf;base64,JVBERi0xLjcNJeLjz9MNCz..."
    },
    {
      "name": "agree",
      "display": "Согласие",
      "type": 4,
      "value": "on",
      "required": true
    }
  ]
}

Поля payload

Поле Тип Описание
form_name string Имя директории формы (без пути).
form_title string Заголовок формы из settings.json.
submitted_at string Время отправки формы (RFC3339).
fields array Массив полей формы с введёнными пользователем значениями.

Каждый элемент fields соответствует полю из settings.json с добавленным заполненным значением:

Поле Описание
name Имя поля (из settings.json).
display Отображаемое название поля.
type Тип поля (1-6, см. выше).
value Заполненное пользователем значение. Для поля "файл" — имя файла. Для чекбокса — "on"/"off".
required Было ли поле обязательным.
multi Для мульти-списка — true.
data Для поля "файл" — Data URI (data:mime;base64,...). Отсутствует для остальных типов.

Миграция: замена SendEmail на webhook

В будущем планируется полностью отказаться от встроенной отправки email через SMTP и вынести её в отдельный микросервис, который будет получать данные через webhook.

Рекомендуемая стратегия:

  1. Добавить webhook с URL вашего email-сервиса в settings.json.
  2. Дождаться, пока email-сервис начнёт стабильно обрабатывать запросы.
  3. Удалить из settings.json все smtp*-поля и опционально — отключить параметр hasEmail.
  4. В коде: удалить вызов SendEmail из route/post.go и сопутствующие файлы (route/send-email.go, lib/mail.go).

Отладка webhook

В репозитории есть микроутилита cmd/webhook/main.go для отладки. Она запускает HTTP-сервер, который выводит в stdout метод, URL, заголовки и тело каждого входящего запроса.

# порт по умолчанию 9999
go run ./cmd/webhook/
# или укажите порт первым аргументом
go run ./cmd/webhook/ 8080

Затем укажите URL http://localhost:9999 (или ваш порт) в webhooks вашего settings.json — и все payloads будут выводиться в терминал.

Доступные дополнительные функции в шаблонизаторе

Все свойства формы доступны из шаблонизатора с той разницей, что первая прописная буква меняется на заглавную за исключением некоторых полей: CSSFiles, CSSExternals, JSFiles, JSExternals. Кроме того для каждого поля есть свойство Error, в которое вписывается ошибка для поля в случае если форма при сохранении не принята, а так же есть корневое поле формы Error для отображения общей информации ошибки.

linkCss

Ссылка на локальный CSS

externalCss

Ссылка на внешний CSS

linkJs

Ссылка на локальный JS

externalJs

Ссылка на внешний JS

linkForm

Ссылка на сохранение формы для аргумента action на форме. Можно применять для других целей, например, для уазания пути на дополнительные статичные файлы для загрузки.

input

Генератор тэга input

label

Генератор тэга label

labelCaptcha

Генератор тэга label для капчи

imageCaptcha

Генератор тэга img для капчи

inputCaptcha

Генератор тэга input для капчи

csrfField

Генератор скрытого поля _csrf для защиты от CSRF-атак. Обязателен к использованию в каждом шаблоне формы внутри тега <form>. Без него POST-запросы будут отклоняться с ошибкой 403.

normalizePath

Нормализация пути ссылки

Параметры запуска

Приложение поддерживает 2 метода передачи параметров запуска: командная строка и переменные окружения.

Для получения списка параметров и переменных окружения достаточно запустить приложение с ключом "--help".