feat: ревизия до обновления цен + короткие ссылки /:code для опти
- При нажатии «обновить цены» создаётся ревизия текущего состояния («до обновления цен») через новый эндпоинт POST /api/configs/:uuid/snapshot, затем saveConfig создаёт ревизию с новыми ценами - Роут GET /:code → редирект на /projects/:uuid по коду опти (регистронезависимо) - Валидация кода опти: только URL-безопасные символы [A-Za-z0-9._-] (бэкенд + клиентская проверка + подсказка в форме) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -894,6 +894,17 @@ func setupRouter(cfg *config.Config, local *localdb.LocalDB, connMgr *db.Connect
|
||||
router.GET("/pricelists/:id", webHandler.PricelistDetail)
|
||||
router.GET("/partnumber-books", webHandler.PartnumberBooks)
|
||||
|
||||
// Short project URL: /:code → redirect to /projects/:uuid
|
||||
router.GET("/:code", func(c *gin.Context) {
|
||||
code := c.Param("code")
|
||||
project, err := projectService.GetByCode(code)
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusFound, "/projects")
|
||||
return
|
||||
}
|
||||
c.Redirect(http.StatusFound, "/projects/"+project.UUID)
|
||||
})
|
||||
|
||||
// htmx partials
|
||||
partials := router.Group("/partials")
|
||||
{
|
||||
@@ -1148,6 +1159,15 @@ func setupRouter(cfg *config.Config, local *localdb.LocalDB, connMgr *db.Connect
|
||||
c.JSON(http.StatusOK, config)
|
||||
})
|
||||
|
||||
configs.POST("/:uuid/snapshot", func(c *gin.Context) {
|
||||
uuid := c.Param("uuid")
|
||||
if err := configService.SnapshotCurrentState(uuid); err != nil {
|
||||
respondError(c, http.StatusInternalServerError, "internal server error", err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
})
|
||||
|
||||
configs.PATCH("/:uuid/project", func(c *gin.Context) {
|
||||
uuid := c.Param("uuid")
|
||||
var req struct {
|
||||
@@ -1517,7 +1537,8 @@ func setupRouter(cfg *config.Config, local *localdb.LocalDB, connMgr *db.Connect
|
||||
project, err := projectService.Create(dbUsername, &req)
|
||||
if err != nil {
|
||||
switch {
|
||||
case errors.Is(err, services.ErrReservedMainVariant):
|
||||
case errors.Is(err, services.ErrReservedMainVariant),
|
||||
errors.Is(err, services.ErrProjectCodeInvalidChars):
|
||||
respondError(c, http.StatusBadRequest, "invalid request", err)
|
||||
case errors.Is(err, services.ErrProjectCodeExists):
|
||||
respondError(c, http.StatusConflict, "conflict detected", err)
|
||||
@@ -1555,7 +1576,8 @@ func setupRouter(cfg *config.Config, local *localdb.LocalDB, connMgr *db.Connect
|
||||
if err != nil {
|
||||
switch {
|
||||
case errors.Is(err, services.ErrReservedMainVariant),
|
||||
errors.Is(err, services.ErrCannotRenameMainVariant):
|
||||
errors.Is(err, services.ErrCannotRenameMainVariant),
|
||||
errors.Is(err, services.ErrProjectCodeInvalidChars):
|
||||
respondError(c, http.StatusBadRequest, "invalid request", err)
|
||||
case errors.Is(err, services.ErrProjectCodeExists):
|
||||
respondError(c, http.StatusConflict, "conflict detected", err)
|
||||
|
||||
Reference in New Issue
Block a user