Language Stack fertig gestellt und dokumentiert

This commit is contained in:
2026-07-26 14:47:20 +02:00
parent 2517600524
commit 28fb522f70
2 changed files with 277 additions and 38 deletions
+151
View File
@@ -1,2 +1,153 @@
# Simply CPQ Buildtime Server # Simply CPQ Buildtime Server
Dieser Ordner enthält alle relevanten Dateien und Informationen zum Simply CPQ Buildtime Server. Dieser dient der Pflege von Produktdaten, Regeln, Konditionen und Administration der Simply CPQ Anwendung durch die Bereitstellung des Pflege-Servers. Dieser Ordner enthält alle relevanten Dateien und Informationen zum Simply CPQ Buildtime Server. Dieser dient der Pflege von Produktdaten, Regeln, Konditionen und Administration der Simply CPQ Anwendung durch die Bereitstellung des Pflege-Servers.
## Open Source Bibliotheken, die hier genutzt werden
### Viper
Viper dient zum Laden uns Auswerten von Config-Dateien. In diesem Case werden die HTTP-Servereinstellungen und die Datenbankverbindung ausgewertet.
````
go get github.com/spf13/viper
````
### PostgreSQL
Die Datenbank des Systems ist in dem Datenbankmanagementsystem PostgreSQL abgelegt. Zum einen braucht es eine Installation des Systems, auf dem die Software Zugriff hat und zum anderen benötigt das System die entsprechenden PostgreSQL Treiber für Go.
````
go get github.com/lib/pq
````
### Gin Gonic
Webserver Library zum Routing der API.
````
go get -u github.com/gin-gonic/gin
````
## Einrichten des Servers:
## Server API
Die Server-API baut auf HTTP und auf REST auf. Antworten werden im JSON Format gesendet,ebenso, wie neu anzulegende Daten oder zu aktualisierende Daten.
### Languages
Dieses Paket dient der Verwaltung der zur Verfügung stehenden Sprachen für die Stammdaten-Übersetzungen.
#### hole alle Sprachen
````
get: http://server:port/languages
````
Dieser Request liefert alle Sprachen im JSON Format. Hier ein beispielhaftes Ergebnis:
````json
[
{
"id": 1,
"locale": "de_DE",
"language": "german"
},
{
"id": 2,
"locale": "en_EN",
"language": "english (EN)"
},
{
"id": 3,
"locale": "en_US",
"language": "english (US)"
},
{
"id": 5,
"locale": "fr-FR",
"language": "france"
},
{
"id": 6,
"locale": "it-IT",
"language": "italy"
}
]
````
#### Hole die Sprache mit einer bestimmten ID
````
get: http://server:port/language/id
z.B.
get: http://server:port/language/5
````
Dieser Request liefert die Sprache im JSON Format mit der angegebenen ID im Pfad. Hier ein beispielhaftes Ergebnis:
````json
{
"id": 5,
"locale": "fr-FR",
"language": "france"
}
````
Der Request mit der ID 4 in diesem Beispiel liefert einen Fehler, da eine Sprache mit der ID 4 nicht existiert:
````
get: http://server:port/language/4
````
#### Aktualisiere eine Sprache
````
put: http://server:port/language
inhalt: application/json
z.B.:
{
"id": 1,
"locale": "de-DE",
"language": "german"
}
````
Alter Datensatz mit falschem locale:
````json
{
"id": 1,
"locale": "de_DE",
"language": "german"
}
````
Neuer, korrigierter Datensatz:
````json
{
"id": 1,
"locale": "de-DE",
"language": "german"
}
````
#### Anlegen einer neuen Sprache
````
put: http://server:port/language
inhalt: application/json
z.B.:
{
"id": 1,
"locale": "de-de",
"language": "german"
}
````
Neuer Datensatz:
````json
{
"id": 7,
"locale": "de-de",
"language": "german"
}
````
ACHTUNG: Die "id" des Datensatzes im Body wurde nicht genutzt. Sie wird bei der Neuanlage von der Datenbank bestimmt.
#### Löschen eines Datensatzes
````
delete: http://server:port/language/id
z.B.:
delete: http://server:port/language/7
````
Der Beispielrequest löscht den im vorherigen Abschnit angelegten Datensatz wieder.
@@ -4,11 +4,13 @@ import (
"database/sql" "database/sql"
"net/http" "net/http"
"scpq-editor-server/models" "scpq-editor-server/models"
"strconv"
) )
type LanguagesRepository struct { type LanguagesRepository struct {
dbHandler *sql.DB dbHandler *sql.DB
} }
func NewLanguagesRepository(dbHandler *sql.DB) *LanguagesRepository { func NewLanguagesRepository(dbHandler *sql.DB) *LanguagesRepository {
return &LanguagesRepository{ return &LanguagesRepository{
dbHandler: dbHandler, dbHandler: dbHandler,
@@ -16,7 +18,7 @@ func NewLanguagesRepository(dbHandler *sql.DB) *LanguagesRepository {
} }
func (rr LanguagesRepository) CreateLanguage(language *models.Language) (*models.Language, *models.ResponseError) { func (rr LanguagesRepository) CreateLanguage(language *models.Language) (*models.Language, *models.ResponseError) {
query:=`INSERT INTO languages(locale, language) VALUES($1,$2) RETURNING id` query := `INSERT INTO languages(locale, language) VALUES($1,$2) RETURNING id`
rows, err := rr.dbHandler.Query(query, language.Locale, language.Language) rows, err := rr.dbHandler.Query(query, language.Locale, language.Language)
if err != nil { if err != nil {
return nil, &models.ResponseError{ return nil, &models.ResponseError{
@@ -26,9 +28,9 @@ func (rr LanguagesRepository) CreateLanguage(language *models.Language) (*models
} }
defer rows.Close() defer rows.Close()
var languageId int var idstr string
for rows.Next() { for rows.Next() {
err := rows.Scan(languageId) err := rows.Scan(&idstr)
if err != nil { if err != nil {
return nil, &models.ResponseError{ return nil, &models.ResponseError{
Message: err.Error(), Message: err.Error(),
@@ -42,6 +44,14 @@ func (rr LanguagesRepository) CreateLanguage(language *models.Language) (*models
Status: http.StatusInternalServerError, Status: http.StatusInternalServerError,
} }
} }
languageId, err := strconv.Atoi(idstr)
if err != nil {
return nil, &models.ResponseError{
Message: "language id not int",
Status: http.StatusInternalServerError,
}
}
return &models.Language{ return &models.Language{
ID: languageId, ID: languageId,
Locale: language.Locale, Locale: language.Locale,
@@ -50,27 +60,99 @@ func (rr LanguagesRepository) CreateLanguage(language *models.Language) (*models
} }
func (rr LanguagesRepository) UpdateLanguage(language *models.Language) *models.ResponseError { func (rr LanguagesRepository) UpdateLanguage(language *models.Language) *models.ResponseError {
query := `UPDATE languages SET locale=$1, language=$2 WHERE id=$3`
res, err := rr.dbHandler.Exec(query, language.Locale, language.Language, language.ID)
if err != nil {
return &models.ResponseError{ return &models.ResponseError{
Message: "UpdateLanguage not yet implementet", Message: err.Error(),
Status: http.StatusInternalServerError, Status: http.StatusInternalServerError,
} }
}
rowsAffeced, err := res.RowsAffected()
if err != nil {
return &models.ResponseError{
Message: err.Error(),
Status: http.StatusInternalServerError,
}
}
if rowsAffeced == 0 {
return &models.ResponseError{
Message: "No language found with the given id",
Status: http.StatusNotFound,
}
}
return nil
} }
func (rr LanguagesRepository) DeleteLanguage(languageId int) *models.ResponseError { func (rr LanguagesRepository) DeleteLanguage(languageId int) *models.ResponseError {
query := `DELETE FROM languages WHERE id=$1`
res, err := rr.dbHandler.Exec(query, languageId)
if err != nil {
return &models.ResponseError{ return &models.ResponseError{
Message: "UpdateLanguage not yet implementet", Message: err.Error(),
Status: http.StatusInternalServerError, Status: http.StatusInternalServerError,
} }
}
rowsAffeced, err := res.RowsAffected()
if err != nil {
return &models.ResponseError{
Message: err.Error(),
Status: http.StatusInternalServerError,
}
}
if rowsAffeced == 0 {
return &models.ResponseError{
Message: "No language found with the given id",
Status: http.StatusNotFound,
}
}
return nil
} }
func (rr LanguagesRepository) GetLanguage(languageId int) (*models.Language, *models.ResponseError) { func (rr LanguagesRepository) GetLanguage(languageId int) (*models.Language, *models.ResponseError) {
query := `SELECT id, locale, language FROM languages WHERE id=$1`
rows, err := rr.dbHandler.Query(query, languageId)
if err != nil {
return nil, &models.ResponseError{ return nil, &models.ResponseError{
Message: "UpdateLanguage not yet implementet", Message: err.Error(),
Status: http.StatusInternalServerError, Status: http.StatusInternalServerError,
} }
}
defer rows.Close()
var idstr, locale, language string
for rows.Next() {
err := rows.Scan(&idstr, &locale, &language)
if err != nil {
return nil, &models.ResponseError{
Message: err.Error(),
Status: http.StatusInternalServerError,
}
}
}
if rows.Err() != nil {
return nil, &models.ResponseError{
Message: err.Error(),
Status: http.StatusInternalServerError,
}
}
if err != nil {
return nil, &models.ResponseError{
Message: "language id not int",
Status: http.StatusInternalServerError,
}
}
return &models.Language{
ID: languageId,
Locale: locale,
Language: language,
}, nil
} }
func (rr LanguagesRepository) GetAllLanguages()([]*models.Language, *models.ResponseError) { func (rr LanguagesRepository) GetAllLanguages() ([]*models.Language, *models.ResponseError) {
query:="SELECT * FROM languages" query := "SELECT id, locale, language FROM languages"
rows, err := rr.dbHandler.Query(query) rows, err := rr.dbHandler.Query(query)
if err != nil { if err != nil {
return nil, &models.ResponseError{ return nil, &models.ResponseError{
@@ -81,17 +163,23 @@ func (rr LanguagesRepository) GetAllLanguages()([]*models.Language, *models.Resp
defer rows.Close() defer rows.Close()
languages := make([]*models.Language, 0) languages := make([]*models.Language, 0)
var id int var idstr, locale, language string
var locale, language string
for rows.Next() { for rows.Next() {
err := rows.Scan(id, locale, language) err := rows.Scan(&idstr, &locale, &language)
if err != nil { if err != nil {
return nil, &models.ResponseError{ return nil, &models.ResponseError{
Message: err.Error(), Message: err.Error(),
Status: http.StatusInternalServerError, Status: http.StatusInternalServerError,
} }
} }
language := &models.Language { id, err := strconv.Atoi(idstr)
if err != nil {
return nil, &models.ResponseError{
Message: "language id not int",
Status: http.StatusInternalServerError,
}
}
language := &models.Language{
ID: id, ID: id,
Locale: locale, Locale: locale,
Language: language, Language: language,