role, rolbinding, right daos

This commit is contained in:
BENEDEK László 2025-06-11 19:07:21 +02:00
parent 3995617db6
commit bd0539cff5
10 changed files with 473 additions and 8 deletions

View File

@ -11,6 +11,9 @@ var channelDAO IChannelDAO
var sessionDAO ISessionDAO var sessionDAO ISessionDAO
var messageDAO IMessageDAO var messageDAO IMessageDAO
var notifcationDAO INotificationDAO var notifcationDAO INotificationDAO
var roleDAO IRoleDAO
var roleBindingDAO IRoleBindingDAO
var rightDAO IRightDAO
func GetUserDAO() (IUserDAO, *util.ChatError) { func GetUserDAO() (IUserDAO, *util.ChatError) {
if userDAO == nil { if userDAO == nil {
@ -51,6 +54,45 @@ func GetMessageDAO() (IMessageDAO, *util.ChatError) {
return messageDAO, nil return messageDAO, nil
} }
func GetRoleDAO() (IRoleDAO, *util.ChatError) {
if roleDAO == nil {
dao, err := postgres.MakeRoleDAO()
if err != nil {
return roleDAO, err
}
roleDAO = dao
}
return roleDAO, nil
}
func GetRoleBindingDAO() (IRoleBindingDAO, *util.ChatError) {
if roleBindingDAO == nil {
dao, err := postgres.MakeRoleBindingDAO()
if err != nil {
return roleBindingDAO, err
}
roleBindingDAO = dao
}
return roleBindingDAO, nil
}
func GetRightDAO() (IRightDAO, *util.ChatError) {
if rightDAO == nil {
dao, err := postgres.MakeRightDAO()
if err != nil {
return rightDAO, err
}
rightDAO = dao
}
return rightDAO, nil
}
func GetSessionDAO() (ISessionDAO, *util.ChatError) { func GetSessionDAO() (ISessionDAO, *util.ChatError) {
if sessionDAO == nil { if sessionDAO == nil {
dao, err := valkey.MakeSessionDAO() dao, err := valkey.MakeSessionDAO()

14
dao/IRightDAO.go Normal file
View File

@ -0,0 +1,14 @@
package dao
import (
"git.tek.govt.hu/dowerx/chat/server/model"
"git.tek.govt.hu/dowerx/chat/server/util"
)
type IRightDAO interface {
Grant(model.Role, model.Channel, model.RightEnum) *util.ChatError
Update(model.Role, model.Channel, model.RightEnum) *util.ChatError
Revoke(model.Role, model.Channel) *util.ChatError
ListRoleRights(model.Role) (map[int]model.RightEnum, *util.ChatError)
ListUserRigths(model.User) (map[int]model.RightEnum, *util.ChatError)
}

13
dao/IRoleBindingDAO.go Normal file
View File

@ -0,0 +1,13 @@
package dao
import (
"git.tek.govt.hu/dowerx/chat/server/model"
"git.tek.govt.hu/dowerx/chat/server/util"
)
type IRoleBindingDAO interface {
Bind(model.Role, model.User) *util.ChatError
Unbind(model.Role, model.User) *util.ChatError
ListRolesOfUser(model.User) ([]model.Role, *util.ChatError)
ListUserWithRole(model.Role) ([]model.User, *util.ChatError)
}

14
dao/IRoleDAO.go Normal file
View File

@ -0,0 +1,14 @@
package dao
import (
"git.tek.govt.hu/dowerx/chat/server/model"
"git.tek.govt.hu/dowerx/chat/server/util"
)
type IRoleDAO interface {
Create(name string) (int, *util.ChatError)
Read(model.Role) (model.Role, *util.ChatError)
List() ([]model.Role, *util.ChatError)
Update(model.Role) *util.ChatError
Delete(model.Role) *util.ChatError
}

146
dao/postgres/RightDAO.go Normal file
View File

@ -0,0 +1,146 @@
package postgres
import (
"git.tek.govt.hu/dowerx/chat/server/model"
"git.tek.govt.hu/dowerx/chat/server/util"
)
type RightDAOPG struct {
pgDAO
}
func (d RightDAOPG) Grant(role model.Role, channel model.Channel, rights model.RightEnum) *util.ChatError {
if role.ID != 0 {
role.Name = ""
}
if channel.ID != 0 {
channel.Name = ""
}
_, err := d.db.Exec(
`insert into "right" ("role_id", "channel_id", "rights") values (
(select "id" from "role" where "id" = $1 or "name" = $2),
(select "id" from "channel" where "id" = $3 or "name" = $4),
$5
)`, role.ID, role.Name, channel.ID, channel.Name, rights)
return util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
func (d RightDAOPG) Revoke(role model.Role, channel model.Channel) *util.ChatError {
if role.ID != 0 {
role.Name = ""
}
if channel.ID != 0 {
channel.Name = ""
}
_, err := d.db.Exec(
`delete from "right"
where
"role_id" = (select "id" from "role" where "id" = $1 or "name" = $2)
and
"channel_id" = (select "id" from "channel" where "id" = $3 or "name" = $4)`,
role.ID, role.Name, channel.ID, channel.Name)
return util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
func (d RightDAOPG) Update(role model.Role, channel model.Channel, rights model.RightEnum) *util.ChatError {
if role.ID != 0 {
role.Name = ""
}
if channel.ID != 0 {
channel.Name = ""
}
_, err := d.db.Exec(
`update "right" set "rights" = $5
where
"role_id" = (select "id" from "role" where "id" = $1 or "name" = $2)
and
"channel_id" = (select "id" from "channel" where "id" = $3 or "name" = $4)`,
role.ID, role.Name, channel.ID, channel.Name, rights)
return util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
func (d RightDAOPG) ListRoleRights(role model.Role) (map[int]model.RightEnum, *util.ChatError) {
if role.ID != 0 {
role.Name = ""
}
rows, err := d.db.NamedQuery(
`select
"channel_id", "rights"
from "rights"
where "role_id" = (select "id" from "role" where "id" = :id or "name" = :name)`,
&role)
if err != nil {
return nil, util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
result := make(map[int]model.RightEnum)
var channel_id int
var rights model.RightEnum
for rows.Next() {
err = rows.Scan(&channel_id, &rights)
if err != nil {
return nil, util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
result[channel_id] = rights
}
return result, nil
}
func (d RightDAOPG) ListUserRigths(user model.User) (map[int]model.RightEnum, *util.ChatError) {
if user.ID != 0 {
user.Username = ""
}
rows, err := d.db.NamedQuery(
`select
"channel_id", "rights"
from "user_rigths_per_channel"
where "user_id" = (select "id" from "user" where "id" = :id or "username" = :username)`,
&user)
if err != nil {
return nil, util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
result := make(map[int]model.RightEnum)
var channel_id int
var rights model.RightEnum
for rows.Next() {
err = rows.Scan(&channel_id, &rights)
if err != nil {
return nil, util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
result[channel_id] = rights
}
return result, nil
}
func MakeRightDAO() (RightDAOPG, *util.ChatError) {
dao := RightDAOPG{}
conn, err := getDatabase()
if err != nil {
return dao, err
}
dao.db = conn
return dao, nil
}

View File

@ -0,0 +1,131 @@
package postgres
import (
"git.tek.govt.hu/dowerx/chat/server/model"
"git.tek.govt.hu/dowerx/chat/server/util"
)
type RoleBindingDAOPG struct {
pgDAO
}
// Bind creates a new RoleBinding.
//
// It uses name only if ID is not set.
func (d RoleBindingDAOPG) Bind(role model.Role, user model.User) *util.ChatError {
if role.ID != 0 {
role.Name = ""
}
if user.ID != 0 {
user.Username = ""
}
_, err := d.db.Exec(
`insert into "role" ("role_id", "user_id") values (
(select "id" from "role" where "id" = $1 or "name" = $2),
(select "id" from "user" where "id" = $3 or "username" = $4))`,
role.ID, role.Name,
user.ID, user.Username)
return util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
// Unbind deletes a RoleBinding.
//
// It uses name only if ID is not set.
func (d RoleBindingDAOPG) Unbind(role model.Role, user model.User) *util.ChatError {
if role.ID != 0 {
role.Name = ""
}
if user.ID != 0 {
user.Username = ""
}
_, err := d.db.Exec(
`delete from "role"
where
"role_id" = (select "id" from "role" where "id" = $1 or "name" = $2)
and
"user_id" = (select "id" from "user" where "id" = $3 or "username" = $4)`,
role.ID, role.Name,
user.ID, user.Username)
return util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
func (d RoleBindingDAOPG) ListRolesOfUser(user model.User) ([]model.Role, *util.ChatError) {
if user.ID != 0 {
user.Username = ""
}
rows, err := d.db.NamedQuery(
`select
"r"."id" as "id",
"r"."name" as "name"
from "role_binding" "rb"
join "role" "r" on "r"."id" = "rb"."role_id"
where "user_id" = (select "id" from "user" where "id" = :id or "username" = :username)`,
&user)
if err != nil {
return nil, util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
var roles []model.Role
for rows.Next() {
role := model.Role{}
err = rows.Scan(&role)
if err != nil {
return nil, util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
roles = append(roles, role)
}
return roles, nil
}
func (d RoleBindingDAOPG) ListUserWithRole(role model.Role) ([]model.User, *util.ChatError) {
if role.ID != 0 {
role.Name = ""
}
rows, err := d.db.NamedQuery(
`select
"u".*
from "user" "u"
join "role_binding" "rb" on "rb"."user_id" = "u"."id"
where "rb"."role_id" = (select "id" from "role" where "id" = :id or "name" = :name)`,
&role)
if err != nil {
return nil, util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
var users []model.User
for rows.Next() {
user := model.User{}
err = rows.Scan(&user)
if err != nil {
return nil, util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
users = append(users, user)
}
return users, nil
}
func MakeRoleBindingDAO() (RoleBindingDAOPG, *util.ChatError) {
dao := RoleBindingDAOPG{}
conn, err := getDatabase()
if err != nil {
return dao, err
}
dao.db = conn
return dao, nil
}

98
dao/postgres/RoleDAO.go Normal file
View File

@ -0,0 +1,98 @@
package postgres
import (
"git.tek.govt.hu/dowerx/chat/server/model"
"git.tek.govt.hu/dowerx/chat/server/util"
"github.com/jmoiron/sqlx"
)
type RoleDAOPG struct {
pgDAO
}
func (d RoleDAOPG) Create(name string) (int, *util.ChatError) {
rows, err := d.db.Query(`insert into "role" ("name") values ($1) returning "id"`, name)
if err != nil {
return 0, util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
if !rows.Next() {
return 0, &util.ChatError{Message: "no id returned by insert", Code: util.DATABASE_QUERY_FAULT}
}
var id int
err = rows.Scan(&id)
return id, util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
func (d RoleDAOPG) Read(role model.Role) (model.Role, *util.ChatError) {
var rows *sqlx.Rows
var err error
if role.ID != 0 {
rows, err = d.db.NamedQuery(`select * from "role" where "id" = :id`, &role)
} else {
rows, err = d.db.NamedQuery(`select * from "role" where "name" = :name`, &role)
}
defer rows.Close()
if err != nil {
return role, util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
if !rows.Next() {
return role, &util.ChatError{Message: "", Code: util.NOT_FOUND}
}
err = rows.StructScan(&role)
return role, util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
func (d RoleDAOPG) List() ([]model.Role, *util.ChatError) {
rows, err := d.db.Queryx(`select * from "role" order by "name"`)
if err != nil {
return nil, util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
defer rows.Close()
roles := make([]model.Role, 0)
for rows.Next() {
role := model.Role{}
err = rows.StructScan(&role)
if err != nil {
break
}
roles = append(roles, role)
}
return roles, util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
func (d RoleDAOPG) Update(role model.Role) *util.ChatError {
_, err := d.db.NamedExec(`update "role" set "name" = :name where "id" = :id`, &role)
return util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
func (d RoleDAOPG) Delete(role model.Role) *util.ChatError {
var err error
if role.ID != 0 {
_, err = d.db.NamedExec(`delete from "role" where "id" = :id`, &role)
} else {
_, err = d.db.NamedExec(`delete from "role" where "name" = :name`, &role)
}
return util.MakeError(err, util.DATABASE_QUERY_FAULT)
}
func MakeRoleDAO() (RoleDAOPG, *util.ChatError) {
dao := RoleDAOPG{}
conn, err := getDatabase()
if err != nil {
return dao, err
}
dao.db = conn
return dao, nil
}

View File

@ -1,7 +1,8 @@
package model package model
type Channel struct { type Channel struct {
ID int `db:"id" json:"id"` ID int `db:"id" json:"id"`
Name string `db:"name" json:"name"` Name string `db:"name" json:"name"`
Description string `db:"description" json:"description"` Description string `db:"description" json:"description"`
Rights RightEnum `db:"rights" json:"rights"`
} }

View File

@ -1,10 +1,10 @@
package model package model
type Right string type RightEnum string
const ( const (
RightRead = "R" RightRead RightEnum = "R"
RightWrite = "W" RightWrite RightEnum = "W"
RightReadWrite = "RW" RightReadWrite RightEnum = "RW"
RightAdmin = "A" RightAdmin RightEnum = "A"
) )

6
model/Role.go Normal file
View File

@ -0,0 +1,6 @@
package model
type Role struct {
ID int `db:"id"`
Name string `db:"name"`
}