|
@@ -1,5 +1,6 @@
|
|
|
# -*- coding:utf-8 -*-
|
|
|
import base64
|
|
|
+import json
|
|
|
import logging
|
|
|
import secrets
|
|
|
import uuid
|
|
@@ -346,6 +347,10 @@ class TenantService:
|
|
|
|
|
|
class RegisterService:
|
|
|
|
|
|
+ @classmethod
|
|
|
+ def _get_invitation_token_key(cls, token: str) -> str:
|
|
|
+ return f'member_invite:token:{token}'
|
|
|
+
|
|
|
@classmethod
|
|
|
def register(cls, email, name, password: str = None, open_id: str = None, provider: str = None) -> Account:
|
|
|
db.session.begin_nested()
|
|
@@ -401,7 +406,7 @@ class RegisterService:
|
|
|
# send email
|
|
|
send_invite_member_mail_task.delay(
|
|
|
to=email,
|
|
|
- token=cls.generate_invite_token(tenant, account),
|
|
|
+ token=token,
|
|
|
inviter_name=inviter.name if inviter else 'Dify',
|
|
|
workspace_id=tenant.id,
|
|
|
workspace_name=tenant.name,
|
|
@@ -412,21 +417,35 @@ class RegisterService:
|
|
|
@classmethod
|
|
|
def generate_invite_token(cls, tenant: Tenant, account: Account) -> str:
|
|
|
token = str(uuid.uuid4())
|
|
|
- email_hash = sha256(account.email.encode()).hexdigest()
|
|
|
- cache_key = 'member_invite_token:{}, {}:{}'.format(str(tenant.id), email_hash, token)
|
|
|
- redis_client.setex(cache_key, 3600, str(account.id))
|
|
|
+ invitation_data = {
|
|
|
+ 'account_id': account.id,
|
|
|
+ 'email': account.email,
|
|
|
+ 'workspace_id': tenant.id,
|
|
|
+ }
|
|
|
+ redis_client.setex(
|
|
|
+ cls._get_invitation_token_key(token),
|
|
|
+ 3600,
|
|
|
+ json.dumps(invitation_data)
|
|
|
+ )
|
|
|
return token
|
|
|
|
|
|
@classmethod
|
|
|
def revoke_token(cls, workspace_id: str, email: str, token: str):
|
|
|
- email_hash = sha256(email.encode()).hexdigest()
|
|
|
- cache_key = 'member_invite_token:{}, {}:{}'.format(workspace_id, email_hash, token)
|
|
|
- redis_client.delete(cache_key)
|
|
|
+ if workspace_id and email:
|
|
|
+ email_hash = sha256(email.encode()).hexdigest()
|
|
|
+ cache_key = 'member_invite_token:{}, {}:{}'.format(workspace_id, email_hash, token)
|
|
|
+ redis_client.delete(cache_key)
|
|
|
+ else:
|
|
|
+ redis_client.delete(cls._get_invitation_token_key(token))
|
|
|
|
|
|
@classmethod
|
|
|
- def get_account_if_token_valid(cls, workspace_id: str, email: str, token: str) -> Optional[Account]:
|
|
|
+ def get_invitation_if_token_valid(cls, workspace_id: str, email: str, token: str) -> Optional[Account]:
|
|
|
+ invitation_data = cls._get_invitation_by_token(token, workspace_id, email)
|
|
|
+ if not invitation_data:
|
|
|
+ return None
|
|
|
+
|
|
|
tenant = db.session.query(Tenant).filter(
|
|
|
- Tenant.id == workspace_id,
|
|
|
+ Tenant.id == invitation_data['workspace_id'],
|
|
|
Tenant.status == 'normal'
|
|
|
).first()
|
|
|
|
|
@@ -435,30 +454,43 @@ class RegisterService:
|
|
|
|
|
|
tenant_account = db.session.query(Account, TenantAccountJoin.role).join(
|
|
|
TenantAccountJoin, Account.id == TenantAccountJoin.account_id
|
|
|
- ).filter(Account.email == email, TenantAccountJoin.tenant_id == tenant.id).first()
|
|
|
+ ).filter(Account.email == invitation_data['email'], TenantAccountJoin.tenant_id == tenant.id).first()
|
|
|
|
|
|
if not tenant_account:
|
|
|
return None
|
|
|
|
|
|
- account_id = cls._get_account_id_by_invite_token(workspace_id, email, token)
|
|
|
- if not account_id:
|
|
|
- return None
|
|
|
-
|
|
|
account = tenant_account[0]
|
|
|
if not account:
|
|
|
return None
|
|
|
|
|
|
- if account_id != str(account.id):
|
|
|
+ if invitation_data['account_id'] != str(account.id):
|
|
|
return None
|
|
|
|
|
|
- return account
|
|
|
+ return {
|
|
|
+ 'account': account,
|
|
|
+ 'data': invitation_data,
|
|
|
+ 'tenant': tenant,
|
|
|
+ }
|
|
|
|
|
|
@classmethod
|
|
|
- def _get_account_id_by_invite_token(cls, workspace_id: str, email: str, token: str) -> Optional[str]:
|
|
|
- email_hash = sha256(email.encode()).hexdigest()
|
|
|
- cache_key = 'member_invite_token:{}, {}:{}'.format(workspace_id, email_hash, token)
|
|
|
- account_id = redis_client.get(cache_key)
|
|
|
- if not account_id:
|
|
|
- return None
|
|
|
+ def _get_invitation_by_token(cls, token: str, workspace_id: str, email: str) -> Optional[str]:
|
|
|
+ if workspace_id is not None and email is not None:
|
|
|
+ email_hash = sha256(email.encode()).hexdigest()
|
|
|
+ cache_key = f'member_invite_token:{workspace_id}, {email_hash}:{token}'
|
|
|
+ account_id = redis_client.get(cache_key)
|
|
|
+
|
|
|
+ if not account_id:
|
|
|
+ return None
|
|
|
+
|
|
|
+ return {
|
|
|
+ 'account_id': account_id.decode('utf-8'),
|
|
|
+ 'email': email,
|
|
|
+ 'workspace_id': workspace_id,
|
|
|
+ }
|
|
|
+ else:
|
|
|
+ data = redis_client.get(cls._get_invitation_token_key(token))
|
|
|
+ if not data:
|
|
|
+ return None
|
|
|
|
|
|
- return account_id.decode('utf-8')
|
|
|
+ invitation = json.loads(data)
|
|
|
+ return invitation
|