Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
canifa_note
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Vũ Hoàng Anh
canifa_note
Commits
51950122
Unverified
Commit
51950122
authored
Jan 01, 2023
by
boojack
Committed by
GitHub
Jan 01, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: add `activity` table (#888)
feat: introduce activity
parent
a797280e
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
217 additions
and
3 deletions
+217
-3
activity.go
api/activity.go
+94
-0
api.go
api/api.go
+3
-0
go.mod
go.mod
+1
-0
go.sum
go.sum
+2
-0
auth.go
server/auth.go
+23
-3
activity.go
store/activity.go
+84
-0
LATEST__SCHEMA.sql
store/db/migration/dev/LATEST__SCHEMA.sql
+10
-0
No files found.
api/activity.go
0 → 100644
View file @
51950122
package
api
// ActivityType is the type for an activity.
type
ActivityType
string
const
(
// User related.
// ActivityUserCreate is the type for creating users.
ActivityUserCreate
ActivityType
=
"user.create"
// ActivityUserUpdate is the type for updating users.
ActivityUserUpdate
ActivityType
=
"user.update"
// ActivityUserDelete is the type for deleting users.
ActivityUserDelete
ActivityType
=
"user.delete"
// ActivityUserAuthSignIn is the type for user signin.
ActivityUserAuthSignIn
ActivityType
=
"user.auth.signin"
// ActivityUserAuthSignUp is the type for user signup.
ActivityUserAuthSignUp
ActivityType
=
"user.auth.signup"
// ActivityUserAuthSignOut is the type for user signout.
ActivityUserAuthSignOut
ActivityType
=
"user.auth.signout"
// ActivityUserSettingUpdate is the type for updating user settings.
ActivityUserSettingUpdate
ActivityType
=
"user.setting.update"
// Memo related.
// ActivityMemoCreate is the type for creating memos.
ActivityMemoCreate
ActivityType
=
"memo.create"
// ActivityMemoUpdate is the type for updating memos.
ActivityMemoUpdate
ActivityType
=
"memo.update"
// ActivityMemoDelete is the type for deleting memos.
ActivityMemoDelete
ActivityType
=
"memo.delete"
// Shortcut related.
// ActivityShortcutCreate is the type for creating shortcuts.
ActivityShortcutCreate
ActivityType
=
"shortcut.create"
// ActivityShortcutUpdate is the type for updating shortcuts.
ActivityShortcutUpdate
ActivityType
=
"shortcut.update"
// ActivityShortcutDelete is the type for deleting shortcuts.
ActivityShortcutDelete
ActivityType
=
"shortcut.delete"
// Tag related.
// ActivityTagCreate is the type for creating tags.
ActivityTagCreate
ActivityType
=
"tag.create"
// ActivityTagDelete is the type for deleting tags.
ActivityTagDelete
ActivityType
=
"tag.delete"
// Server related.
// ActivityServerStart is the type for starting server.
ActivityServerStart
ActivityType
=
"server.start"
)
// ActivityLevel is the level of activities.
type
ActivityLevel
string
const
(
// ActivityInfo is the INFO level of activities.
ActivityInfo
ActivityLevel
=
"INFO"
// ActivityWarn is the WARN level of activities.
ActivityWarn
ActivityLevel
=
"WARN"
// ActivityError is the ERROR level of activities.
ActivityError
ActivityLevel
=
"ERROR"
)
type
ActivityUserAuthSignInPayload
struct
{
UserID
int
`json:"userId"`
IP
string
`json:"ip"`
}
type
Activity
struct
{
ID
int
`json:"id"`
// Standard fields
CreatorID
int
`json:"creatorId"`
CreatedTs
int64
`json:"createdTs"`
// Domain specific fields
Type
ActivityType
`json:"type"`
Level
ActivityLevel
`json:"level"`
Payload
string
`json:"payload"`
}
// ActivityCreate is the API message for creating an activity.
type
ActivityCreate
struct
{
// Standard fields
CreatorID
int
// Domain specific fields
Type
ActivityType
`json:"type"`
Level
ActivityLevel
Payload
string
`json:"payload"`
}
api/api.go
View file @
51950122
package
api
package
api
// UnknownID is the ID for unknowns.
const
UnknownID
=
-
1
// RowStatus is the status for a row.
// RowStatus is the status for a row.
type
RowStatus
string
type
RowStatus
string
...
...
go.mod
View file @
51950122
...
@@ -46,6 +46,7 @@ require (
...
@@ -46,6 +46,7 @@ require (
)
)
require (
require (
github.com/pkg/errors v0.9.1
github.com/segmentio/analytics-go v3.1.0+incompatible
github.com/segmentio/analytics-go v3.1.0+incompatible
golang.org/x/exp v0.0.0-20221217163422-3c43f8badb15
golang.org/x/exp v0.0.0-20221217163422-3c43f8badb15
)
)
go.sum
View file @
51950122
...
@@ -45,6 +45,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
...
@@ -45,6 +45,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
...
...
server/auth.go
View file @
51950122
...
@@ -5,6 +5,7 @@ import (
...
@@ -5,6 +5,7 @@ import (
"fmt"
"fmt"
"net/http"
"net/http"
"github.com/pkg/errors"
"github.com/usememos/memos/api"
"github.com/usememos/memos/api"
"github.com/usememos/memos/common"
"github.com/usememos/memos/common"
metric
"github.com/usememos/memos/plugin/metrics"
metric
"github.com/usememos/memos/plugin/metrics"
...
@@ -43,9 +44,9 @@ func (s *Server) registerAuthRoutes(g *echo.Group) {
...
@@ -43,9 +44,9 @@ func (s *Server) registerAuthRoutes(g *echo.Group) {
if
err
=
setUserSession
(
c
,
user
);
err
!=
nil
{
if
err
=
setUserSession
(
c
,
user
);
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to set signin session"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to set signin session"
)
.
SetInternal
(
err
)
}
}
s
.
Collector
.
Collect
(
ctx
,
&
metric
.
Metric
{
if
err
:=
s
.
createUserAuthSignInActivity
(
c
,
user
);
err
!=
nil
{
Name
:
"user signed in"
,
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to create activity"
)
.
SetInternal
(
err
)
}
)
}
c
.
Response
()
.
Header
()
.
Set
(
echo
.
HeaderContentType
,
echo
.
MIMEApplicationJSONCharsetUTF8
)
c
.
Response
()
.
Header
()
.
Set
(
echo
.
HeaderContentType
,
echo
.
MIMEApplicationJSONCharsetUTF8
)
if
err
:=
json
.
NewEncoder
(
c
.
Response
()
.
Writer
)
.
Encode
(
composeResponse
(
user
));
err
!=
nil
{
if
err
:=
json
.
NewEncoder
(
c
.
Response
()
.
Writer
)
.
Encode
(
composeResponse
(
user
));
err
!=
nil
{
...
@@ -143,3 +144,22 @@ func (s *Server) registerAuthRoutes(g *echo.Group) {
...
@@ -143,3 +144,22 @@ func (s *Server) registerAuthRoutes(g *echo.Group) {
return
c
.
JSON
(
http
.
StatusOK
,
true
)
return
c
.
JSON
(
http
.
StatusOK
,
true
)
})
})
}
}
func
(
s
*
Server
)
createUserAuthSignInActivity
(
c
echo
.
Context
,
user
*
api
.
User
)
error
{
ctx
:=
c
.
Request
()
.
Context
()
payload
:=
api
.
ActivityUserAuthSignInPayload
{
UserID
:
user
.
ID
,
IP
:
echo
.
ExtractIPFromRealIPHeader
()(
c
.
Request
()),
}
payloadStr
,
err
:=
json
.
Marshal
(
payload
)
if
err
!=
nil
{
return
errors
.
Wrap
(
err
,
"failed to malshal activity payload"
)
}
_
,
err
=
s
.
Store
.
CreateActivity
(
ctx
,
&
api
.
ActivityCreate
{
CreatorID
:
user
.
ID
,
Type
:
api
.
ActivityUserAuthSignIn
,
Level
:
api
.
ActivityInfo
,
Payload
:
string
(
payloadStr
),
})
return
err
}
store/activity.go
0 → 100644
View file @
51950122
package
store
import
(
"context"
"database/sql"
"github.com/usememos/memos/api"
)
// activityRaw is the store model for an Activity.
// Fields have exactly the same meanings as Activity.
type
activityRaw
struct
{
ID
int
// Standard fields
CreatorID
int
CreatedTs
int64
// Domain specific fields
Type
api
.
ActivityType
Level
api
.
ActivityLevel
Payload
string
}
// toActivity creates an instance of Activity based on the ActivityRaw.
func
(
raw
*
activityRaw
)
toActivity
()
*
api
.
Activity
{
return
&
api
.
Activity
{
ID
:
raw
.
ID
,
CreatorID
:
raw
.
CreatorID
,
CreatedTs
:
raw
.
CreatedTs
,
Type
:
raw
.
Type
,
Level
:
raw
.
Level
,
Payload
:
raw
.
Payload
,
}
}
// CreateActivity creates an instance of Activity.
func
(
s
*
Store
)
CreateActivity
(
ctx
context
.
Context
,
create
*
api
.
ActivityCreate
)
(
*
api
.
Activity
,
error
)
{
tx
,
err
:=
s
.
db
.
BeginTx
(
ctx
,
nil
)
if
err
!=
nil
{
return
nil
,
FormatError
(
err
)
}
defer
tx
.
Rollback
()
activityRaw
,
err
:=
createActivity
(
ctx
,
tx
,
create
)
if
err
!=
nil
{
return
nil
,
err
}
if
err
:=
tx
.
Commit
();
err
!=
nil
{
return
nil
,
FormatError
(
err
)
}
return
activityRaw
.
toActivity
(),
nil
}
// createActivity creates a new activity.
func
createActivity
(
ctx
context
.
Context
,
tx
*
sql
.
Tx
,
create
*
api
.
ActivityCreate
)
(
*
activityRaw
,
error
)
{
query
:=
`
INSERT INTO activity (
creator_id,
type,
level,
payload
)
VALUES (?, ?, ?, ?)
RETURNING id, type, level, payload, creator_id, created_ts
`
var
activityRaw
activityRaw
if
err
:=
tx
.
QueryRowContext
(
ctx
,
query
,
create
.
CreatorID
,
create
.
Type
,
create
.
Level
,
create
.
Payload
)
.
Scan
(
&
activityRaw
.
ID
,
&
activityRaw
.
Type
,
&
activityRaw
.
Level
,
&
activityRaw
.
Payload
,
&
activityRaw
.
CreatedTs
,
&
activityRaw
.
CreatedTs
,
);
err
!=
nil
{
return
nil
,
FormatError
(
err
)
}
return
&
activityRaw
,
nil
}
store/db/migration/dev/LATEST__SCHEMA.sql
View file @
51950122
...
@@ -93,3 +93,13 @@ CREATE TABLE tag (
...
@@ -93,3 +93,13 @@ CREATE TABLE tag (
creator_id
INTEGER
NOT
NULL
,
creator_id
INTEGER
NOT
NULL
,
UNIQUE
(
name
,
creator_id
)
UNIQUE
(
name
,
creator_id
)
);
);
-- activity
CREATE
TABLE
activity
(
id
INTEGER
PRIMARY
KEY
AUTOINCREMENT
,
creator_id
INTEGER
NOT
NULL
,
created_ts
BIGINT
NOT
NULL
DEFAULT
(
strftime
(
'%s'
,
'now'
)),
type
TEXT
NOT
NULL
DEFAULT
''
,
level
TEXT
NOT
NULL
CHECK
(
level
IN
(
'INFO'
,
'WARN'
,
'ERROR'
))
DEFAULT
'INFO'
,
payload
TEXT
NOT
NULL
DEFAULT
'{}'
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment