Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
movacheckin
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
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
vicotor
movacheckin
Commits
f5c52da4
Commit
f5c52da4
authored
Aug 29, 2025
by
vicotor
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add new func
parent
cb1ed766
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
193 additions
and
22 deletions
+193
-22
config.toml
supabase/config.toml
+11
-0
.npmrc
supabase/functions/check_sign/.npmrc
+3
-0
deno.json
supabase/functions/check_sign/deno.json
+3
-0
index.ts
supabase/functions/check_sign/index.ts
+150
-0
index.ts
supabase/functions/sign/index.ts
+26
-22
No files found.
supabase/config.toml
View file @
f5c52da4
...
...
@@ -355,3 +355,14 @@ entrypoint = "./functions/sign_time_range/index.ts"
# Specifies static files to be bundled with the function. Supports glob patterns.
# For example, if you want to serve static HTML pages in your function:
# static_files = [ "./functions/sign_time_range/*.html" ]
[functions.check_sign]
enabled
=
true
verify_jwt
=
true
import_map
=
"./functions/check_sign/deno.json"
# Uncomment to specify a custom file path to the entrypoint.
# Supported file extensions are: .ts, .js, .mjs, .jsx, .tsx
entrypoint
=
"./functions/check_sign/index.ts"
# Specifies static files to be bundled with the function. Supports glob patterns.
# For example, if you want to serve static HTML pages in your function:
# static_files = [ "./functions/check_sign/*.html" ]
supabase/functions/check_sign/.npmrc
0 → 100644
View file @
f5c52da4
# Configuration for private npm package dependencies
# For more information on using private registries with Edge Functions, see:
# https://supabase.com/docs/guides/functions/import-maps#importing-from-private-registries
supabase/functions/check_sign/deno.json
0 → 100644
View file @
f5c52da4
{
"imports"
:
{}
}
supabase/functions/check_sign/index.ts
0 → 100644
View file @
f5c52da4
// supabase/functions/sign/index.ts
import
"
jsr:@supabase/functions-js/edge-runtime.d.ts
"
;
import
{
createClient
}
from
'
jsr:@supabase/supabase-js@2
'
;
console
.
log
(
"
Sign function started
"
)
const
corsHeaders
=
{
'
Access-Control-Allow-Origin
'
:
'
*
'
,
'
Access-Control-Allow-Headers
'
:
'
authorization, x-client-info, apikey, content-type
'
};
// Haversine公式计算距离
function
calculateDistance
(
lat1
:
number
,
lon1
:
number
,
lat2
:
number
,
lon2
:
number
):
number
{
const
R
=
6371
// 地球半径(千米)
const
dLat
=
(
lat2
-
lat1
)
*
Math
.
PI
/
180
const
dLon
=
(
lon2
-
lon1
)
*
Math
.
PI
/
180
const
a
=
Math
.
sin
(
dLat
/
2
)
*
Math
.
sin
(
dLat
/
2
)
+
Math
.
cos
(
lat1
*
Math
.
PI
/
180
)
*
Math
.
cos
(
lat2
*
Math
.
PI
/
180
)
*
Math
.
sin
(
dLon
/
2
)
*
Math
.
sin
(
dLon
/
2
)
const
c
=
2
*
Math
.
atan2
(
Math
.
sqrt
(
a
),
Math
.
sqrt
(
1
-
a
))
return
R
*
c
}
Deno
.
serve
(
async
(
req
)
=>
{
if
(
req
.
method
===
'
OPTIONS
'
)
{
return
new
Response
(
'
ok
'
,
{
headers
:
corsHeaders
});
}
try
{
// 获取用户认证信息
const
authHeader
=
req
.
headers
.
get
(
'
Authorization
'
);
if
(
!
authHeader
)
{
console
.
error
(
'
no auth header
'
)
return
new
Response
(
JSON
.
stringify
({
error
:
'
No Authorization
'
}),
{
status
:
401
,
headers
:
{
...
corsHeaders
,
'
Content-Type
'
:
'
application/json
'
}
});
}
// 创建Supabase客户端
const
supabaseClient
=
createClient
(
Deno
.
env
.
get
(
'
SUPABASE_URL
'
)
??
''
,
Deno
.
env
.
get
(
'
SUPABASE_ANON_KEY
'
)
??
''
,
{
global
:
{
headers
:
{
Authorization
:
authHeader
}
}
});
// 获取当前用户
const
{
data
:
{
user
},
error
:
userError
}
=
await
supabaseClient
.
auth
.
getUser
();
if
(
userError
||
!
user
)
{
console
.
error
(
'
Auth error:
'
,
userError
)
return
new
Response
(
JSON
.
stringify
({
error
:
'
Auth Fail
'
,
details
:
userError
?.
message
}),
{
status
:
401
,
headers
:
{
...
corsHeaders
,
'
Content-Type
'
:
'
application/json
'
}
});
}
// 获取签到配置
const
{
data
:
config
,
error
:
configError
}
=
await
supabaseClient
.
from
(
'
sign_config
'
)
.
select
(
'
*
'
)
.
order
(
'
created_at
'
,
{
ascending
:
false
})
.
limit
(
1
)
.
single
()
if
(
configError
||
!
config
)
{
console
.
error
(
'
get sign config error:
'
,
configError
)
return
new
Response
(
JSON
.
stringify
({
success
:
false
,
message
:
'
not found config
'
}),
{
status
:
500
,
headers
:
{
...
corsHeaders
,
'
Content-Type
'
:
'
application/json
'
}
})
}
// 从 invitation 表中 获取用户信息.
const
{
data
:
userInfo
,
error
:
getError
}
=
await
supabaseClient
.
from
(
'
invitation
'
)
.
select
(
'
*
'
)
.
eq
(
'
user_id
'
,
user
.
id
)
.
limit
(
1
)
.
single
()
if
(
getError
)
{
console
.
error
(
'
Get user info error:
'
,
getError
)
return
new
Response
(
JSON
.
stringify
({
success
:
false
,
message
:
'
User info fetch failed
'
}),
{
headers
:
{
...
corsHeaders
,
'
Content-Type
'
:
'
application/json
'
}
})
}
if
(
!
userInfo
.
in_white_list
)
{
// 验证时间范围
const
now
=
new
Date
()
const
beijingTime
=
new
Date
(
now
.
getTime
()
+
(
8
*
60
*
60
*
1000
))
const
startTime
=
new
Date
(
config
.
start_time
)
const
endTime
=
new
Date
(
config
.
end_time
)
console
.
info
(
`Current Beijing time:
${
beijingTime
.
toISOString
()}
, Sign time range:
${
startTime
.
toISOString
()}
-
${
endTime
.
toISOString
()}
`
)
if
(
beijingTime
<
startTime
||
beijingTime
>
endTime
)
{
console
.
error
(
'
Not in sign time range
'
)
return
new
Response
(
JSON
.
stringify
({
success
:
false
,
message
:
'
not in sign time range
'
}),
{
status
:
400
,
headers
:
{
...
corsHeaders
,
'
Content-Type
'
:
'
application/json
'
}
})
}
}
else
{
console
.
info
(
`User
${
user
.
id
}
is in the whitelist, skipping time range check.`
)
}
return
new
Response
(
JSON
.
stringify
({
success
:
true
,
message
:
'
success
'
}),
{
headers
:
{
...
corsHeaders
,
'
Content-Type
'
:
'
application/json
'
}
})
}
catch
(
error
)
{
console
.
error
(
'
Function error:
'
,
error
)
return
new
Response
(
JSON
.
stringify
({
success
:
false
,
message
:
'
Internal error
'
}),
{
status
:
500
,
headers
:
{
...
corsHeaders
,
'
Content-Type
'
:
'
application/json
'
}
})
}
})
\ No newline at end of file
supabase/functions/sign/index.ts
View file @
f5c52da4
...
...
@@ -118,23 +118,6 @@ Deno.serve(async (req) => {
})
}
// 验证时间范围
const
now
=
new
Date
()
const
beijingTime
=
new
Date
(
now
.
getTime
()
+
(
8
*
60
*
60
*
1000
))
const
startTime
=
new
Date
(
config
.
start_time
)
const
endTime
=
new
Date
(
config
.
end_time
)
console
.
info
(
`Current Beijing time:
${
beijingTime
.
toISOString
()}
, Sign time range:
${
startTime
.
toISOString
()}
-
${
endTime
.
toISOString
()}
`
)
if
(
beijingTime
<
startTime
||
beijingTime
>
endTime
)
{
console
.
error
(
'
Not in sign time range
'
)
return
new
Response
(
JSON
.
stringify
({
success
:
false
,
message
:
'
not in sign time range
'
}),
{
status
:
400
,
headers
:
{
...
corsHeaders
,
'
Content-Type
'
:
'
application/json
'
}
})
}
// 从 invitation 表中 获取用户签到状态.
...
...
@@ -146,15 +129,36 @@ Deno.serve(async (req) => {
.
single
()
if
(
getError
)
{
console
.
error
(
'
Get sign status error:
'
,
getError
)
console
.
error
(
'
Get sign status error:
'
,
getError
)
return
new
Response
(
JSON
.
stringify
({
success
:
false
,
message
:
'
User sign status fetch failed
'
}),
{
headers
:
{
...
corsHeaders
,
'
Content-Type
'
:
'
application/json
'
}
})
}
if
(
!
userInfo
.
in_white_list
)
{
// 验证时间范围
const
now
=
new
Date
()
const
beijingTime
=
new
Date
(
now
.
getTime
()
+
(
8
*
60
*
60
*
1000
))
const
startTime
=
new
Date
(
config
.
start_time
)
const
endTime
=
new
Date
(
config
.
end_time
)
console
.
info
(
`Current Beijing time:
${
beijingTime
.
toISOString
()}
, Sign time range:
${
startTime
.
toISOString
()}
-
${
endTime
.
toISOString
()}
`
)
if
(
beijingTime
<
startTime
||
beijingTime
>
endTime
)
{
console
.
error
(
'
Not in sign time range
'
)
return
new
Response
(
JSON
.
stringify
({
success
:
false
,
message
:
'
User sign status fetch failed
'
success
:
false
,
message
:
'
not in sign time range
'
}),
{
headers
:
{
...
corsHeaders
,
'
Content-Type
'
:
'
application/json
'
}
status
:
400
,
headers
:
{
...
corsHeaders
,
'
Content-Type
'
:
'
application/json
'
}
})
}
}
else
{
console
.
info
(
`User
${
user_id
}
is in the whitelist, skipping time range check`
)
}
// console.log(`Fetched user info: ${JSON.stringify(userInfo)}`)
if
(
userInfo
.
is_signed
)
{
console
.
error
(
'
User has already signed in
'
,
user
.
id
)
...
...
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