- Go 95.6%
- Go Template 2.7%
- CSS 0.9%
- Dockerfile 0.4%
- HTML 0.4%
|
|
||
|---|---|---|
| .vscode | ||
| cmd | ||
| db | ||
| forms/test | ||
| http | ||
| lib | ||
| log | ||
| middleware | ||
| route | ||
| structs | ||
| tmpl | ||
| .dockerignore | ||
| .gitignore | ||
| .golangci.yml | ||
| .woodpecker.yml | ||
| coverage.out | ||
| Dockerfile | ||
| Dockerfile.amd64 | ||
| go.mod | ||
| go.sum | ||
| README.md | ||
| ROADMAP.md | ||
| TODO | ||
Генератор регистрационных форм на различные мероприятия
Приложение предназначено для создание шаблонов форм регистрации на различные мероприятия (конференции, семинары, собрания и т.д.). Приложение перебирает директории из указанной. Каждая директория является отдельной самостоятельной формой и из нее ищет файл 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.
Рекомендуемая стратегия:
- Добавить webhook с URL вашего email-сервиса в settings.json.
- Дождаться, пока email-сервис начнёт стабильно обрабатывать запросы.
- Удалить из settings.json все
smtp*-поля и опционально — отключить параметрhasEmail. - В коде: удалить вызов
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".