8000 login: profile builder && session builder by molon · Pull Request #407 · qor5/admin · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
8000

login: profile builder && session builder #407

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 40 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
f157a8e
activity: add error returns for currentUserFunc
molon Jul 21, 2024
fed64b8
profile: without login sessions
molon Jul 21, 2024
b60a848
profile: compo vpre
molon Jul 21, 2024
bed3c5b
Merge branch 'main' into profile
molon Jul 22, 2024
51896d8
profile: customize Status text
molon Jul 22, 2024
39ed699
login: move session_mgmt logic to login package
molon Jul 22, 2024
0e797ed
login session dialog
molon Jul 24, 2024
b26f6d8
go mod tidy
molon Jul 24, 2024
ba19d58
Merge branch 'main' into profile
molon Jul 24, 2024
80f32fa
Merge branch 'main' into profile
molon Jul 24, 2024
4741dfe
fix DataOperator call timing
molon Jul 24, 2024
b541257
Merge branch 'main' into profile
molon Jul 24, 2024
12b6da2
activity.ObjectID => presets.ObjectID
molon Jul 24, 2024
eb4c73a
make creating reuse the editing logic, unless Wrap is not used
molon Jul 24, 2024
f70602d
activity: rm ActionLastView select option in ActivityLogs menu
molon Jul 24, 2024
b8b838e
activity: tableNamePrefix without admin
molon Jul 25, 2024
2c543b3
activity: TablePrefix complete
molon Jul 25, 2024
195b69b
8000 activity: rm ActionView from DefaultActions
molon Jul 25, 2024
1294964
activity: uix name use table name without schema
molon Jul 25, 2024
e41773f
activity: fix markAllNotesAsRead
molon Jul 26, 2024
31e3052
activity: change the usage of markAllNotesAsRead
molon Jul 26, 2024
94a1327
activity: tidy comments
molon Jul 26, 2024
cd30b0e
activity: optional installation of admin ui
molon Jul 26, 2024
e6099a2
activity: ShowMessage use const var
molon Jul 26, 2024
7c2b9e1
activity: creator => user
molon Jul 26, 2024
f7fc1dc
fix tests
molon Jul 26, 2024
a072935
activity: ensure call TablePrefix before AutoMigrate
molon Jul 26, 2024
7325440
activity: util.Fetch func returns error
molon Jul 28, 2024
e42b97a
activity: README
molon Jul 28, 2024
a0eeaf0
Merge branch 'main' into profile
molon Jul 28, 2024
434e1fa
profile: package => login
molon Jul 28, 2024
f0d69f8
login: use presets.MustObjectID
molon Jul 29, 2024
cec1123
Merge branch 'main' into profile
molon Aug 1, 2024
0db688d
profile: fix ui
molon Aug 1, 2024
e50933c
login session: support multitenant
molon Aug 1, 2024
827f22b
profile: sync unread notes count
molon Aug 1, 2024
52306cf
activity: HasUnreadCount Filter methods
molon Aug 1, 2024
8346fc3
fix TestProfile
molon Aug 1, 2024
178ca07
Merge branch 'main' into profile
molon Aug 1, 2024
dbba76d
profile: test profile compo ui
molon Aug 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions activity/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
- Firstly, you should create an activity instance in your project.

```go
activity := activity.New(db, currentUserFunc)
ab := activity.New(db, currentUserFunc).
TablePrefix("cms_"). // if needed
AutoMigrate() // if needed
```

- db (Required): The database where activity_logs is stored.
Expand All @@ -14,28 +16,28 @@
- Register activity into presets

```go
activityBuilder.Install(presetsBuilder)
ab.Install(presetsBuilder)
```

- Register normal model or a `presets.ModelBuilder` into activity

```go
activity.RegisterModel(normalModel) // It need you to record the activity log manually
activity.RegisterModel(presetModel) // It will record the activity log automatically when you create, update or delete the model data via preset admin
ab.RegisterModel(normalModel) // It need you to record the activity log manually
ab.RegisterModel(presetModel) // It will record the activity log automatically when you create, update or delete the model data via preset admin
```

- Skip recording activity log for preset model if you don't want to record the activity log automatically

```go
activity.RegisterModel(presetModel).SkipCreate().SkipUpdate().SkipDelete()
ab.RegisterModel(presetModel).SkipCreate().SkipUpdate().SkipDelete()
```

- Configure more options for the `presets.ModelBuilder` to record more custom information

```go
activity.RegisterModel(presetModel).AddKeys("ID", "Version") // will record value of the ID and Version field as the keyword of a model table
activity.RegisterModel(presetModel).AddIgnoredFields("UpdateAt") // will ignore the UpdateAt field when recording activity log for update operation
activity.RegisterModel(presetModel).AddTypeHanders(
ab.RegisterModel(presetModel).AddKeys("ID", "Version") // will record value of the ID and Version field as the keyword of a model table
ab.RegisterModel(presetModel).AddIgnoredFields("UpdateAt") // will ignore the UpdateAt field when recording activity log for update operation
ab.RegisterModel(presetModel).AddTypeHanders(
time.Time{},
func(old, new any, prefixField string) []Diff {
oldString := old.(time.Time).Format(time.RFC3339)
Expand All @@ -55,15 +57,15 @@
- When a struct type only have one `activity.ModelBuilder`, you can use `activity` to record the log directly.

```go
activity.OnEdit(ctx, old, new)
activity.OnCreate(ctx, obj)
ab.OnEdit(ctx, old, new)
ab.OnCreate(ctx, obj)
```

- When a struct type have multiple `activity.ModelBuilder`, you need to get the corresponding `activity.ModelBuilder` and then use it to record the log.

```go
activity.MustGetModelBuilder(presetModel1).OnEdit(ctx, old, new)
activity.MustGetModelBuilder(presetModel2).OnCreate(ctx, obj)
ab.MustGetModelBuilder(presetModel1).OnEdit(ctx, old, new)
ab.MustGetModelBuilder(presetModel2).OnCreate(ctx, obj)
```

- Add ListFieldNotes to Listing Builder
Expand Down
4 changes: 2 additions & 2 deletions activity/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@
lb.Field("ModelLabel").Label(Messages_en_US.ModelLabel).ComponentFunc(
func(obj any, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
if obj.(*ActivityLog).ModelLabel == "" {
return h.Td(h.Text("-"))
return h.Td(h.Text(NopModelLabel))

Check warning on line 150 in activity/admin.go

View check run for this annotation

Codecov / codecov/patch

activity/admin.go#L150

Added line #L150 was not covered by tests
}
return h.Td(h.Div().Attr("v-pre", true).Text(obj.(*ActivityLog).ModelLabel))
},
Expand Down Expand Up @@ -301,7 +301,7 @@
h.Tr(h.Td(h.Text(msgr.ModelName)), h.Td().Attr("v-pre", true).Text(
i18n.T(ctx.R, presets.ModelsI18nModuleKey, obj.(*ActivityLog).ModelName),
)),
h.Tr(h.Td(h.Text(msgr.ModelLabel)), h.Td().Attr("v-pre", true).Text(cmp.Or(log.ModelLabel, "-"))),
h.Tr(h.Td(h.Text(msgr.ModelLabel)), h.Td().Attr("v-pre", true).Text(cmp.Or(log.ModelLabel, NopModelLabel))),

Check warning on line 304 in activity/admin.go

View check run for this annotation

Codecov / codecov/patch

activity/admin.go#L304

Added line #L304 was not covered by tests
h.Tr(h.Td(h.Text(msgr.ModelKeys)), h.Td().Attr("v-pre", true).Text(log.ModelKeys)),
h.Iff(log.ModelLink != "", func() h.HTMLComponent {
return h.Tr(h.Td(h.Text(msgr.ModelLink)), h.Td(
Expand Down
6 changes: 3 additions & 3 deletions activity/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
if prefix == "" {
ab.db = ab.dbPrimitive
} else {
ab.db = ab.dbPrimitive.Scopes(scopeWithTablePrefix(prefix)).Session(&gorm.Session{})
ab.db = ab.dbPrimitive.Scopes(ScopeWithTablePrefix(prefix)).Session(&gorm.Session{})
}
return ab
}
Expand Down Expand Up @@ -161,7 +161,7 @@

func AutoMigrate(db *gorm.DB, tablePrefix string) error {
if tablePrefix != "" {
db = db.Scopes(scopeWithTablePrefix(tablePrefix)).Session(&gorm.Session{})
db = db.Scopes(ScopeWithTablePrefix(tablePrefix)).Session(&gorm.Session{})
}
dst := []any{&ActivityLog{}, &ActivityUser{}}
for _, v := range dst {
Expand Down Expand Up @@ -241,7 +241,7 @@
if ok {
return bare, nil
}
return nil, errors.Errorf("multiple model builders found for %v", v)
return nil, errors.Errorf("multiple preset model builders found for %v", v)

Check warning on line 244 in activity/builder.go

View check run for this annotation

Codecov / codecov/patch

activity/builder.go#L244

Added line #L244 was not covered by tests
}
return ambs[0], nil
}
Expand Down
11 changes: 6 additions & 5 deletions activity/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/qor5/admin/v3/presets"
"github.com/qor5/admin/v3/presets/gorm2op"
"github.com/qor5/web/v3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/theplant/testenv"
"gorm.io/gorm"
Expand Down Expand Up @@ -343,10 +342,12 @@ func TestMutliModelBuilder(t *testing.T) {
// add edit record
data1.Title = "test1-1"
data1.Description = "Description1-1"
old, _ := FetchOld(db, data1)
db.Save(data1)
_, err := builder.OnEdit(ctx, old, data1)
assert.NoError(t, err)

old, err := FetchOld(db, data1)
require.NoError(t, err)
require.NoError(t, db.Save(data1).Error)
_, err = builder.OnEdit(ctx, old, data1)
require.NoError(t, err)

data2.Title = "test2-1"
data2.Description = "Description2-1"
Expand Down
8 changes: 8 additions & 0 deletions activity/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ type Messages struct {

ActivityLogs string
ActivityLog string

FilterTabsHasUnreadNotes string
}

func (msgr *Messages) LastEditedAt(desc string) string {
Expand Down Expand Up @@ -157,6 +159,8 @@ var Messages_en_US = &Messages{

ActivityLogs: "Activity Logs",
ActivityLog: "Activity Log",

FilterTabsHasUnreadNotes: "Has Unread Notes",
}

var Messages_zh_CN = &Messages{
Expand Down Expand Up @@ -223,6 +227,8 @@ var Messages_zh_CN = &Messages{

ActivityLogs: "操作日志",
ActivityLog: "操作日志",

FilterTabsHasUnreadNotes: "未读备注",
}

var Messages_ja_JP = &Messages{
Expand Down Expand Up @@ -289,4 +295,6 @@ var Messages_ja_JP = &Messages{

ActivityLogs: "アクティビティ履歴",
ActivityLog: "アクティビティ履歴",

FilterTabsHasUnreadNotes: "未読ノート",
}
6 changes: 4 additions & 2 deletions activity/model_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ const (
FieldTimeline string = "__ActivityTimeline__"
ListFieldNotes string = "__ActivityNotes__"
ListFieldLabelNotes string = "Notes"

NopModelLabel = "-"
)

const (
Expand Down Expand Up @@ -52,7 +54,7 @@ type ModelBuilder struct {
type ctxKeyUnreadCounts struct{}

func NotifiLastViewedAtUpdated(modelName string) string {
return fmt.Sprintf("activity_NotifModelsCreated_%s", modelName)
return fmt.Sprintf("activity_NotifiLastViewedAtUpdated_%s", modelName)
}

type PayloadLastViewedAtUpdated struct {
Expand Down Expand Up @@ -472,7 +474,7 @@ func (mb *ModelBuilder) create(
Action: action,
ModelName: modelName,
ModelKeys: modelKeys,
ModelLabel: "-",
ModelLabel: "",
ModelLink: modelLink,
}
if mb.presetModel != nil {
Expand Down
39 changes: 37 additions & 2 deletions activity/note.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,23 @@
import (
"context"
"fmt"
"net/url"
"strings"
"time"

"github.com/pkg/errors"
"github.com/qor5/admin/v3/presets"
"github.com/qor5/web/v3"
"github.com/qor5/x/v3/i18n"
vx "github.com/qor5/x/v3/ui/vuetifyx"
"github.com/samber/lo"
"gorm.io/gorm"
)

type NoteCount struct {
ModelName string
ModelKeys string
ModelLabel string
UnreadNotesCount int64
TotalNotesCount int64
}
Expand Down Expand Up @@ -56,7 +62,7 @@

raw := fmt.Sprintf(`
WITH NoteRecords AS (
SELECT model_name, model_keys, created_at, user_id
SELECT model_name, model_keys, model_label, created_at, user_id
FROM %s
WHERE action = ? AND deleted_at IS NULL
%s
Expand All @@ -71,6 +77,7 @@
SELECT
n.model_name,
n.model_keys,
MAX(n.model_label) AS model_label,
COUNT(CASE WHEN n.user_id <> ? AND (lva.last_viewed_at IS NULL OR n.created_at > lva.last_viewed_at) THEN 1 END) AS unread_notes_count,
COUNT(*) AS total_notes_count
FROM NoteRecords n
Expand Down Expand Up @@ -166,7 +173,7 @@
)

SELECT
%s
%s
FROM NoteRecords n
LEFT JOIN LastViewedAts lva
ON n.model_name = lva.model_name
Expand Down Expand Up @@ -202,3 +209,31 @@
}
return sqlConditionHasUnreadNotes(amb.ab.db, amb.ab.tablePrefix, user.ID, ParseModelName(amb.ref), amb.keyColumns, ModelKeysSeparator, columnPrefix)
}

const KeyHasUnreadNotes = "hasUnreadNotes"

func (amb *ModelBuilder) NewHasUnreadNotesFilterItem(ctx context.Context, columnPrefix string) (*vx.FilterItem, error) {
hasUnreadNotesCondition, err := amb.SQLConditionHasUnreadNotes(ctx, columnPrefix)
if err != nil {
return nil, err

Check warning on line 218 in activity/note.go

View check run for this annotation

Codecov / codecov/patch

activity/note.go#L218

Added line #L218 was not covered by tests
}
return &vx.FilterItem{
Key: KeyHasUnreadNotes,
Invisible: true,
SQLCondition: hasUnreadNotesCondition,
}, nil
}

func (amb *ModelBuilder) NewHasUnreadNotesFilterTab(ctx context.Context) (*presets.FilterTab, error) {
evCtx := web.MustGetEventContext(ctx)
msgr := i18n.MustGetModuleMessages(evCtx.R, I18nActivityKey, Messages_en_US).(*Messages)
return &presets.FilterTab{
Label: msgr.FilterTabsHasUnreadNotes,
ID: KeyHasUnreadNotes,
Query: url.Values{KeyHasUnreadNotes: []string{"1"}},
}, nil
}

func GetHasUnreadNotesHref(listingHref string) string {
return fmt.Sprintf("/%s?active_filter_tab=%s&f_%s=1", listingHref, KeyHasUnreadNotes, KeyHasUnreadNotes)

Check warning on line 238 in activity/note.go

View check run for this annotation

Codecov / codecov/patch

activity/note.go#L237-L238

Added lines #L237 - L238 were not covered by tests
}
33 changes: 16 additions & 17 deletions activity/util.go
F438
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,10 @@

const dbKeyTablePrefix = "__table_prefix__"

// scopeWithTablePrefix set table prefix
// ScopeWithTablePrefix set table prefix
// 1. Only scenarios where a Model is provided are supported
// 2. Previously Table(...) will be overwritten
func scopeWithTablePrefix(tablePrefix string) func(db *gorm.DB) *gorm.DB {
func ScopeWithTablePrefix(tablePrefix string) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
if v, ok := db.Get(dbKeyTablePrefix); ok {
if v.(string) != tablePrefix {
Expand Down Expand Up @@ -157,7 +157,7 @@
return label
}

func FetchOldWithSlug(db *gorm.DB, ref any, slug string) (any, bool) {
func FetchOldWithSlug(db *gorm.DB, ref any, slug string) (any, error) {

Check warning on line 160 in activity/util.go

View check run for this annotation

Codecov / codecov/patch

activity/util.go#L160

Added line #L160 was not covered by tests
if slug == "" {
return FetchOld(db, ref)
}
Expand All @@ -176,28 +176,27 @@
db = db.Where("id = ?", slug)
}

if db.First(old).Error != nil {
return nil, false
if err := db.First(old).Error; err != nil {
return nil, errors.Wrap(err, "fetch old with slug")

Check warning on line 180 in activity/util.go

View check run for this annotation

Codecov / codecov/patch

activity/util.go#L179-L180

Added lines #L179 - L180 were not covered by tests
}

return old, true
return old, nil

Check warning on line 183 in activity/util.go

View check run for this annotation

Codecov / codecov/patch

activity/util.go#L183

Added line #L183 was not covered by tests
}

func FetchOld(db *gorm.DB, ref any) (any, bool) {
func FetchOld(db *gorm.DB, ref any) (any, error) {
var (
rtRef = reflect.Indirect(reflect.ValueOf(ref))
old = reflect.New(rtRef.Type()).Interface()
sqls []string
vars []any
)

stmt := &gorm.Statement{DB: db}
if err := stmt.Parse(ref); err != nil {
return nil, false
s, err := ParseSchemaWithDB(db, ref)
if err != nil {
return nil, err

Check warning on line 196 in activity/util.go

View check run for this annotation

Codecov / codecov/patch

activity/util.go#L196

Added line #L196 was not covered by tests
}

for _, dbName := range stmt.Schema.DBNames {
if field := stmt.Schema.LookUpField(dbName); field != nil && field.PrimaryKey {
for _, dbName := range s.DBNames {
if field := s.LookUpField(dbName); field != nil && field.PrimaryKey {
if value, isZero := field.ValueOf(db.Statement.Context, rtRef); !isZero {
sqls = append(sqls, fmt.Sprintf("%v = ?", dbName))
vars = append(vars, value)
Expand All @@ -206,12 +205,12 @@
}

if len(sqls) == 0 || len(vars) == 0 || len(sqls) != len(vars) {
return nil, false
return nil, errors.New("no primary key found")

Check warning on line 208 in activity/util.go

View check run for this annotation

Codecov / codecov/patch

activity/util.go#L208

Added line #L208 was not covered by tests
}

if db.Where(strings.Join(sqls, " AND "), vars...).First(old).Error != nil {
return nil, false
if err := db.Where(strings.Join(sqls, " AND "), vars...).First(old).Error; err != nil {
return nil, errors.Wrap(err, "fetch old")

Check warning on line 212 in activity/util.go

View check run for this annotation

Codecov / codecov/patch

activity/util.go#L212

Added line #L212 was not covered by tests
}

return old, true
return old, nil
}
Loading
Loading
0