feat(tasks): add typesense indexing
This commit is contained in:
303
pkg/models/typesense.go
Normal file
303
pkg/models/typesense.go
Normal file
@ -0,0 +1,303 @@
|
||||
// Vikunja is a to-do list application to facilitate your life.
|
||||
// Copyright 2018-2023 Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public Licensee as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public Licensee for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public Licensee
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"fmt"
|
||||
|
||||
"github.com/typesense/typesense-go/typesense"
|
||||
"github.com/typesense/typesense-go/typesense/api"
|
||||
"github.com/typesense/typesense-go/typesense/api/pointer"
|
||||
)
|
||||
|
||||
var typesenseClient *typesense.Client
|
||||
|
||||
func InitTypesense() {
|
||||
if !config.TypesenseEnabled.GetBool() {
|
||||
return
|
||||
}
|
||||
|
||||
typesenseClient = typesense.NewClient(
|
||||
typesense.WithServer(config.TypesenseURL.GetString()),
|
||||
typesense.WithAPIKey(config.TypesenseAPIKey.GetString()))
|
||||
}
|
||||
|
||||
func CreateTypesenseCollections() error {
|
||||
taskSchema := &api.CollectionSchema{
|
||||
Name: "tasks",
|
||||
EnableNestedFields: pointer.True(),
|
||||
Fields: []api.Field{
|
||||
{
|
||||
Name: "id",
|
||||
Type: "string",
|
||||
},
|
||||
{
|
||||
Name: "title",
|
||||
Type: "string",
|
||||
},
|
||||
{
|
||||
Name: "description",
|
||||
Type: "string",
|
||||
},
|
||||
{
|
||||
Name: "done",
|
||||
Type: "bool",
|
||||
},
|
||||
{
|
||||
Name: "done_at",
|
||||
Type: "int64", // unix timestamp
|
||||
Optional: pointer.True(),
|
||||
},
|
||||
{
|
||||
Name: "due_date",
|
||||
Type: "int64", // unix timestamp
|
||||
Optional: pointer.True(),
|
||||
},
|
||||
{
|
||||
Name: "project_id",
|
||||
Type: "int64",
|
||||
},
|
||||
{
|
||||
Name: "repeat_after",
|
||||
Type: "int64",
|
||||
},
|
||||
{
|
||||
Name: "repeat_mode",
|
||||
Type: "int32",
|
||||
},
|
||||
{
|
||||
Name: "priority",
|
||||
Type: "int64",
|
||||
},
|
||||
{
|
||||
Name: "start_date",
|
||||
Type: "int64", // unix timestamp
|
||||
Optional: pointer.True(),
|
||||
},
|
||||
{
|
||||
Name: "end_date",
|
||||
Type: "int64", // unix timestamp
|
||||
Optional: pointer.True(),
|
||||
},
|
||||
{
|
||||
Name: "hex_color",
|
||||
Type: "string",
|
||||
},
|
||||
{
|
||||
Name: "percent_done",
|
||||
Type: "float",
|
||||
},
|
||||
{
|
||||
Name: "identifier",
|
||||
Type: "string",
|
||||
},
|
||||
{
|
||||
Name: "index",
|
||||
Type: "int64",
|
||||
},
|
||||
{
|
||||
Name: "uid",
|
||||
Type: "string",
|
||||
},
|
||||
{
|
||||
Name: "cover_image_attachment_id",
|
||||
Type: "int64",
|
||||
},
|
||||
{
|
||||
Name: "created",
|
||||
Type: "int64", // unix timestamp
|
||||
},
|
||||
{
|
||||
Name: "updated",
|
||||
Type: "int64", // unix timestamp
|
||||
},
|
||||
{
|
||||
Name: "bucket_id",
|
||||
Type: "int64",
|
||||
},
|
||||
{
|
||||
Name: "position",
|
||||
Type: "float",
|
||||
},
|
||||
{
|
||||
Name: "kanban_position",
|
||||
Type: "float",
|
||||
},
|
||||
{
|
||||
Name: "created_by_id",
|
||||
Type: "int64",
|
||||
},
|
||||
{
|
||||
Name: "reminders",
|
||||
Type: "object[]", // TODO
|
||||
Optional: pointer.True(),
|
||||
},
|
||||
{
|
||||
Name: "assignees",
|
||||
Type: "object[]", // TODO
|
||||
Optional: pointer.True(),
|
||||
},
|
||||
{
|
||||
Name: "labels",
|
||||
Type: "object[]", // TODO
|
||||
Optional: pointer.True(),
|
||||
},
|
||||
{
|
||||
Name: "related_tasks",
|
||||
Type: "object[]", // TODO
|
||||
Optional: pointer.True(),
|
||||
},
|
||||
{
|
||||
Name: "attachments",
|
||||
Type: "object[]", // TODO
|
||||
Optional: pointer.True(),
|
||||
},
|
||||
{
|
||||
Name: "comments",
|
||||
Type: "object[]", // TODO
|
||||
Optional: pointer.True(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// delete any collection which might exist
|
||||
_, _ = typesenseClient.Collection("tasks").Delete()
|
||||
|
||||
_, err := typesenseClient.Collections().Create(taskSchema)
|
||||
return err
|
||||
}
|
||||
|
||||
func ReindexAllTasks() (err error) {
|
||||
tasks := make(map[int64]*Task)
|
||||
|
||||
s := db.NewSession()
|
||||
defer s.Close()
|
||||
|
||||
err = s.Find(tasks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = addMoreInfoToTasks(s, tasks, &user.User{ID: 1})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, task := range tasks {
|
||||
searchTask := convertTaskToTypesenseTask(task)
|
||||
|
||||
comment := &TaskComment{TaskID: task.ID}
|
||||
searchTask.Comments, _, _, err = comment.ReadAll(s, task.CreatedBy, "", -1, -1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = typesenseClient.Collection("tasks").
|
||||
Documents().
|
||||
Create(searchTask)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type typesenseTask struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Done bool `json:"done"`
|
||||
DoneAt int64 `json:"done_at"`
|
||||
DueDate int64 `json:"due_date"`
|
||||
ProjectID int64 `json:"project_id"`
|
||||
RepeatAfter int64 `json:"repeat_after"`
|
||||
RepeatMode int `json:"repeat_mode"`
|
||||
Priority int64 `json:"priority"`
|
||||
StartDate int64 `json:"start_date"`
|
||||
EndDate int64 `json:"end_date"`
|
||||
HexColor string `json:"hex_color"`
|
||||
PercentDone float64 `json:"percent_done"`
|
||||
Identifier string `json:"identifier"`
|
||||
Index int64 `json:"index"`
|
||||
UID string `json:"uid"`
|
||||
CoverImageAttachmentID int64 `json:"cover_image_attachment_id"`
|
||||
Created int64 `json:"created"`
|
||||
Updated int64 `json:"updated"`
|
||||
BucketID int64 `json:"bucket_id"`
|
||||
Position float64 `json:"position"`
|
||||
KanbanPosition float64 `json:"kanban_position"`
|
||||
CreatedByID int64 `json:"created_by_id"`
|
||||
Reminders interface{} `json:"reminders"`
|
||||
Assignees interface{} `json:"assignees"`
|
||||
Labels interface{} `json:"labels"`
|
||||
//RelatedTasks interface{} `json:"related_tasks"`
|
||||
Attachments interface{} `json:"attachments"`
|
||||
Comments interface{} `json:"comments"`
|
||||
}
|
||||
|
||||
func convertTaskToTypesenseTask(task *Task) *typesenseTask {
|
||||
tt := &typesenseTask{
|
||||
ID: fmt.Sprintf("%d", task.ID),
|
||||
Title: task.Title,
|
||||
Description: task.Description,
|
||||
Done: task.Done,
|
||||
DoneAt: task.DoneAt.UTC().Unix(),
|
||||
DueDate: task.DueDate.UTC().Unix(),
|
||||
ProjectID: task.ProjectID,
|
||||
RepeatAfter: task.RepeatAfter,
|
||||
RepeatMode: int(task.RepeatMode),
|
||||
Priority: task.Priority,
|
||||
StartDate: task.StartDate.UTC().Unix(),
|
||||
EndDate: task.EndDate.UTC().Unix(),
|
||||
HexColor: task.HexColor,
|
||||
PercentDone: task.PercentDone,
|
||||
Identifier: task.Identifier,
|
||||
Index: task.Index,
|
||||
UID: task.UID,
|
||||
CoverImageAttachmentID: task.CoverImageAttachmentID,
|
||||
Created: task.Created.UTC().Unix(),
|
||||
Updated: task.Updated.UTC().Unix(),
|
||||
BucketID: task.BucketID,
|
||||
Position: task.Position,
|
||||
KanbanPosition: task.KanbanPosition,
|
||||
CreatedByID: task.CreatedByID,
|
||||
Reminders: task.Reminders,
|
||||
Assignees: task.Assignees,
|
||||
Labels: task.Labels,
|
||||
//RelatedTasks: task.RelatedTasks,
|
||||
Attachments: task.Attachments,
|
||||
}
|
||||
|
||||
if task.DoneAt.IsZero() {
|
||||
tt.DoneAt = 0
|
||||
}
|
||||
if task.DueDate.IsZero() {
|
||||
tt.DueDate = 0
|
||||
}
|
||||
if task.StartDate.IsZero() {
|
||||
tt.StartDate = 0
|
||||
}
|
||||
if task.EndDate.IsZero() {
|
||||
tt.EndDate = 0
|
||||
}
|
||||
|
||||
return tt
|
||||
}
|
Reference in New Issue
Block a user