work
This commit is contained in:
parent
b57cb700ec
commit
ea2bb235a2
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,4 +1,4 @@
|
|||||||
/frontend/node_modules/
|
/webapp/node_modules/
|
||||||
/frontend/dist/
|
/webapp/dist/
|
||||||
clortho.db
|
clortho.db
|
||||||
clortho_test.db
|
clortho_test.db
|
||||||
|
|||||||
15
.idea/dataSources.xml
generated
Normal file
15
.idea/dataSources.xml
generated
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||||
|
<data-source source="LOCAL" name="clortho" uuid="b0ddef5e-e0d8-4b5a-94f1-84ba070ba818">
|
||||||
|
<driver-ref>sqlite.xerial</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/clortho.db</jdbc-url>
|
||||||
|
<jdbc-additional-properties>
|
||||||
|
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
|
||||||
|
</jdbc-additional-properties>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@ -1,9 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"clortho/apis"
|
"clortho/lib/apis"
|
||||||
"clortho/db"
|
"clortho/lib/db"
|
||||||
"clortho/users"
|
"clortho/lib/users"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"log"
|
"log"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -7,6 +7,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func SetupRouter(r *gin.Engine, authMiddleware gin.HandlerFunc) {
|
func SetupRouter(r *gin.Engine, authMiddleware gin.HandlerFunc) {
|
||||||
|
r.NoRoute(func(c *gin.Context) {
|
||||||
|
c.JSON(http.StatusNotFound, gin.H{
|
||||||
|
"error": "Resource not found",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
private := r.Group("/gui")
|
private := r.Group("/gui")
|
||||||
// Gets the session from the cookie, and puts it in the current request.
|
// Gets the session from the cookie, and puts it in the current request.
|
||||||
if authMiddleware != nil {
|
if authMiddleware != nil {
|
||||||
@ -1,13 +1,33 @@
|
|||||||
package apis
|
package apis
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"clortho/lib/db"
|
||||||
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
// Set up test database file
|
||||||
|
os.Setenv("CLORTHO_DB_FILE", "clortho_test.db")
|
||||||
|
// Global setup
|
||||||
|
fmt.Println("Setting up resources...")
|
||||||
|
|
||||||
|
db.InitDb()
|
||||||
|
defer db.ResetDb()
|
||||||
|
|
||||||
|
exitCode := m.Run() // Run all tests
|
||||||
|
|
||||||
|
// Global teardown
|
||||||
|
fmt.Println("Cleaning up resources...")
|
||||||
|
|
||||||
|
os.Exit(exitCode)
|
||||||
|
}
|
||||||
|
|
||||||
func TestPingRoute(t *testing.T) {
|
func TestPingRoute(t *testing.T) {
|
||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
SetupRouter(r, nil)
|
SetupRouter(r, nil)
|
||||||
@ -1,8 +1,8 @@
|
|||||||
package apis
|
package apis
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"clortho/db"
|
"clortho/lib/db"
|
||||||
"clortho/users"
|
"clortho/lib/users"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
package apis
|
package apis
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"clortho/db"
|
"clortho/lib/db"
|
||||||
"clortho/users"
|
"clortho/lib/users"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1,38 +1,18 @@
|
|||||||
package apis
|
package apis
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"clortho/db"
|
|
||||||
"clortho/users"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
// Set up test database file
|
|
||||||
os.Setenv("CLORTHO_DB_FILE", "clortho_test.db")
|
|
||||||
// Global setup
|
|
||||||
fmt.Println("Setting up resources...")
|
|
||||||
|
|
||||||
db.InitDb()
|
|
||||||
defer db.ResetDb()
|
|
||||||
|
|
||||||
exitCode := m.Run() // Run all tests
|
|
||||||
|
|
||||||
// Global teardown
|
|
||||||
fmt.Println("Cleaning up resources...")
|
|
||||||
|
|
||||||
os.Exit(exitCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInitAuthEndpoints_authSignin(t *testing.T) {
|
func TestInitAuthEndpoints_authSignin(t *testing.T) {
|
||||||
adminPass, err := users.InitAdminUser()
|
_, err := InitUser("admin", "password")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -40,7 +20,7 @@ func TestInitAuthEndpoints_authSignin(t *testing.T) {
|
|||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
SetupRouter(r, nil)
|
SetupRouter(r, nil)
|
||||||
|
|
||||||
reqBody := loginRequest{Username: "admin", Password: *adminPass}
|
reqBody := loginRequest{Username: "admin", Password: "password"}
|
||||||
strReqBody, _ := json.Marshal(reqBody)
|
strReqBody, _ := json.Marshal(reqBody)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
req, _ := http.NewRequest("POST", "/gui/auth/signin", strings.NewReader(string(strReqBody)))
|
req, _ := http.NewRequest("POST", "/gui/auth/signin", strings.NewReader(string(strReqBody)))
|
||||||
@ -53,7 +33,7 @@ func TestInitAuthEndpoints_authSignin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInitAuthEndpoints_authSignout(t *testing.T) {
|
func TestInitAuthEndpoints_authSignout(t *testing.T) {
|
||||||
adminPass, err := users.InitAdminUser()
|
_, err := InitUser("admin", "admin")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -61,7 +41,7 @@ func TestInitAuthEndpoints_authSignout(t *testing.T) {
|
|||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
SetupRouter(r, nil)
|
SetupRouter(r, nil)
|
||||||
|
|
||||||
reqBody := loginRequest{Username: "admin", Password: *adminPass}
|
reqBody := loginRequest{Username: "admin", Password: "admin"}
|
||||||
strReqBody, _ := json.Marshal(reqBody)
|
strReqBody, _ := json.Marshal(reqBody)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
req, _ := http.NewRequest("POST", "/gui/auth/signout", strings.NewReader(string(strReqBody)))
|
req, _ := http.NewRequest("POST", "/gui/auth/signout", strings.NewReader(string(strReqBody)))
|
||||||
@ -1,7 +1,7 @@
|
|||||||
package apis
|
package apis
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"clortho/users"
|
"clortho/lib/users"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
18
lib/apis/systems_endpoints.go
Normal file
18
lib/apis/systems_endpoints.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package apis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"clortho/lib/users"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func InitSystemsEndpoints(r *gin.RouterGroup) {
|
||||||
|
group := r.Group("/users")
|
||||||
|
group.Use(LoggedInMiddleware())
|
||||||
|
group.GET("/", getUsers)
|
||||||
|
group.GET("/me", getMe)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getServers(c *gin.Context) {
|
||||||
|
userList := users.GetUsers()
|
||||||
|
c.JSON(200, &userList)
|
||||||
|
}
|
||||||
32
lib/apis/systems_endpoints_test.go
Normal file
32
lib/apis/systems_endpoints_test.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package apis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInitSystemsEndpoints_getSystems(t *testing.T) {
|
||||||
|
_, err := InitUser("admin", "password")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := gin.Default()
|
||||||
|
SetupRouter(r, nil)
|
||||||
|
|
||||||
|
reqBody := loginRequest{Username: "admin", Password: "password"}
|
||||||
|
strReqBody, _ := json.Marshal(reqBody)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
req, _ := http.NewRequest("POST", "/gui/auth/signin", strings.NewReader(string(strReqBody)))
|
||||||
|
r.ServeHTTP(w, req)
|
||||||
|
|
||||||
|
assert.Equal(t, 200, w.Code)
|
||||||
|
assert.JSONEq(t, `{"valid": true}`, w.Body.String())
|
||||||
|
setCookie := w.Header().Get("Set-Cookie")
|
||||||
|
assert.True(t, strings.Contains(setCookie, "CLORTHO_AUTH="))
|
||||||
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
package apis
|
package apis
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"clortho/users"
|
"clortho/lib/users"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,15 +26,15 @@ type User struct {
|
|||||||
type UserSession struct {
|
type UserSession struct {
|
||||||
ClorthoModel
|
ClorthoModel
|
||||||
|
|
||||||
UserID uint `gorm:"not null" json:"-"`
|
UserID uint `gorm:"not null" json:"-"`
|
||||||
User User `gorm:"foreignKey:UserID" json:"user"`
|
User *User `gorm:"foreignKey:UserID" json:"user"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Key struct {
|
type Key struct {
|
||||||
ClorthoModel
|
ClorthoModel
|
||||||
|
|
||||||
UserID uint `gorm:"not null" json:"-"`
|
UserID uint `gorm:"not null" json:"-"`
|
||||||
User User `gorm:"foreignKey:UserID" json:"user"`
|
User *User `gorm:"foreignKey:UserID" json:"user"`
|
||||||
Content string `gorm:"not null" json:"-" json:"content"`
|
Content string `gorm:"not null" json:"-" json:"content"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,10 +64,10 @@ type SystemGroup struct {
|
|||||||
type Grant struct {
|
type Grant struct {
|
||||||
ClorthoModel
|
ClorthoModel
|
||||||
|
|
||||||
UserID uint `gorm:"not null" json:"-"`
|
UserID uint `gorm:"not null" json:"-"`
|
||||||
User User `gorm:"foreignKey:UserID" json:"user"`
|
User User `gorm:"foreignKey:UserID" json:"user"`
|
||||||
SystemID uint `gorm:"not null" json:"-"`
|
SystemID uint `gorm:"not null" json:"-"`
|
||||||
System System `gorm:"foreignKey:SystemID" json:"system"`
|
System *System `gorm:"foreignKey:SystemID" json:"system"`
|
||||||
GrantedByID uint `gorm:"not null" json:"-"`
|
GrantedByID uint `gorm:"not null" json:"-"`
|
||||||
GrantedBy User `gorm:"foreignKey:GrantedByID" json:"grantedBy"`
|
GrantedBy *User `gorm:"foreignKey:GrantedByID" json:"grantedBy"`
|
||||||
}
|
}
|
||||||
18
lib/systems/systems.go
Normal file
18
lib/systems/systems.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package systems
|
||||||
|
|
||||||
|
import "clortho/lib/db"
|
||||||
|
|
||||||
|
func CreateSystem(name string) (*db.System, error) {
|
||||||
|
system := db.System{Name: name}
|
||||||
|
result := db.Connection.Create(&system)
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
return &system, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSystems() []db.System {
|
||||||
|
var systems []db.System
|
||||||
|
db.Connection.Find(&systems)
|
||||||
|
return systems
|
||||||
|
}
|
||||||
24
lib/systems/systems_test.go
Normal file
24
lib/systems/systems_test.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package systems
|
||||||
|
|
||||||
|
import (
|
||||||
|
"clortho/lib/db"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
// Global setup
|
||||||
|
fmt.Println("Setting up resources...")
|
||||||
|
|
||||||
|
db.InitDb()
|
||||||
|
|
||||||
|
exitCode := m.Run() // Run all tests
|
||||||
|
|
||||||
|
// Global teardown
|
||||||
|
fmt.Println("Cleaning up resources...")
|
||||||
|
|
||||||
|
db.ResetDb()
|
||||||
|
|
||||||
|
os.Exit(exitCode)
|
||||||
|
}
|
||||||
@ -1,8 +1,8 @@
|
|||||||
package users
|
package users
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"clortho/db"
|
"clortho/lib/db"
|
||||||
"clortho/utils"
|
"clortho/lib/utils"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -64,7 +64,7 @@ func GetUsers() []db.User {
|
|||||||
|
|
||||||
func GetSession(id uint) *db.UserSession {
|
func GetSession(id uint) *db.UserSession {
|
||||||
var session db.UserSession
|
var session db.UserSession
|
||||||
result := db.Connection.First(&session, id)
|
result := db.Connection.Joins("User").First(&session, id)
|
||||||
if result.RowsAffected != 0 {
|
if result.RowsAffected != 0 {
|
||||||
return &session
|
return &session
|
||||||
} else {
|
} else {
|
||||||
@ -151,7 +151,7 @@ func GenerateJwt(sessionId uint) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewSession(user db.User) *db.UserSession {
|
func NewSession(user db.User) *db.UserSession {
|
||||||
session := db.UserSession{User: user}
|
session := db.UserSession{User: &user}
|
||||||
db.Connection.Create(&session)
|
db.Connection.Create(&session)
|
||||||
return &session
|
return &session
|
||||||
}
|
}
|
||||||
@ -1,8 +1,8 @@
|
|||||||
package users
|
package users
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"clortho/db"
|
"clortho/lib/db"
|
||||||
"clortho/utils"
|
"clortho/lib/utils"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
0
frontend/.gitignore → webapp/.gitignore
vendored
0
frontend/.gitignore → webapp/.gitignore
vendored
0
frontend/env.d.ts → webapp/env.d.ts
vendored
0
frontend/env.d.ts → webapp/env.d.ts
vendored
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 526 B After Width: | Height: | Size: 526 B |
@ -18,19 +18,23 @@
|
|||||||
v-bind="props"
|
v-bind="props"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<div>
|
<v-card>
|
||||||
{{ appStore.user.displayName }}
|
<v-card-title v-if="appStore.user">
|
||||||
<v-list>
|
Hello {{ appStore.user?.displayName }}
|
||||||
<v-list-item
|
</v-card-title>
|
||||||
v-for="(item, index) in items"
|
<v-card-text class="pa-0">
|
||||||
:key="index"
|
<v-list>
|
||||||
:value="index"
|
<v-list-item
|
||||||
:to="item.link"
|
v-for="(item, index) in items"
|
||||||
>
|
:key="index"
|
||||||
<v-list-item-title>{{ item.title }}</v-list-item-title>
|
:value="index"
|
||||||
</v-list-item>
|
:to="item.link"
|
||||||
</v-list>
|
>
|
||||||
</div>
|
<v-list-item-title>{{ item.title }}</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
</v-menu>
|
</v-menu>
|
||||||
</v-app-bar>
|
</v-app-bar>
|
||||||
|
|
||||||
@ -66,6 +66,12 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {ref} from 'vue'
|
import {ref} from 'vue'
|
||||||
|
|
||||||
|
definePage({
|
||||||
|
meta: {
|
||||||
|
public: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const valid = ref(false)
|
const valid = ref(false)
|
||||||
const username = ref('')
|
const username = ref('')
|
||||||
@ -90,7 +96,7 @@ async function login() {
|
|||||||
// For now, we'll just simulate a successful login
|
// For now, we'll just simulate a successful login
|
||||||
console.log('Login attempted with:', {username: username.value, password: password.value})
|
console.log('Login attempted with:', {username: username.value, password: password.value})
|
||||||
|
|
||||||
const res = await fetch("/gui/auth/login", {
|
const res = await fetch("/gui/auth/signin", {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@ -2,12 +2,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await fetch('/gui/auth/signout', {
|
await fetch('/gui/auth/signout', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
})
|
})
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
await router.replace("/")
|
await router.replace("/")
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@ -3,9 +3,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
/**
|
definePage({
|
||||||
* @route
|
meta: {
|
||||||
* @meta public true
|
public: true
|
||||||
* @meta title "Home"
|
}
|
||||||
*/
|
})
|
||||||
</script>
|
</script>
|
||||||
Loading…
x
Reference in New Issue
Block a user