mayureshagashe2105 commited on
Commit
5cd9bab
·
1 Parent(s): 9d46fc2

Add email verification on singup

Browse files
TechdocsAPI/backend/__init__.py CHANGED
@@ -3,6 +3,7 @@ from mysql.connector import errorcode
3
 
4
  from fastapi import FastAPI, status
5
  from fastapi.exceptions import HTTPException
 
6
 
7
  from backend.utils import DBConnection
8
  from backend.core.ConfigEnv import config
@@ -11,6 +12,8 @@ from langchain.llms import Clarifai
11
  from langchain.chains import LLMChain
12
  from langchain.prompts import PromptTemplate
13
 
 
 
14
  app = FastAPI(title="Techdocs",
15
  version="V0.0.1",
16
  description="API for automatic code documentation generation!"
@@ -43,6 +46,27 @@ try:
43
  app.state.llmchain = llmchain
44
 
45
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  except mysql.connector.Error as err:
47
  raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(err))
48
 
 
3
 
4
  from fastapi import FastAPI, status
5
  from fastapi.exceptions import HTTPException
6
+ from fastapi.templating import Jinja2Templates
7
 
8
  from backend.utils import DBConnection
9
  from backend.core.ConfigEnv import config
 
12
  from langchain.chains import LLMChain
13
  from langchain.prompts import PromptTemplate
14
 
15
+ from fastapi_mail import ConnectionConfig, FastMail
16
+
17
  app = FastAPI(title="Techdocs",
18
  version="V0.0.1",
19
  description="API for automatic code documentation generation!"
 
46
  app.state.llmchain = llmchain
47
 
48
 
49
+ conf = ConnectionConfig(
50
+ MAIL_USERNAME=config.MAIL_USERNAME,
51
+ MAIL_PASSWORD=config.MAIL_PASSWORD,
52
+ MAIL_FROM=config.MAIL_FROM,
53
+ MAIL_PORT=587,
54
+ MAIL_SERVER="smtp.gmail.com",
55
+ MAIL_STARTTLS=True,
56
+ MAIL_SSL_TLS=False,
57
+ TEMPLATE_FOLDER="backend/templates",
58
+ USE_CREDENTIALS = True,
59
+ VALIDATE_CERTS = True
60
+
61
+ # MAIL_TLS=True,
62
+ # MAIL_SSL=False
63
+ )
64
+
65
+ app.state.mail_client = FastMail(conf)
66
+ app.state.templates = Jinja2Templates(directory="./backend/templates")
67
+
68
+
69
+
70
  except mysql.connector.Error as err:
71
  raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(err))
72
 
TechdocsAPI/backend/core/ConfigEnv.py CHANGED
@@ -13,12 +13,17 @@ class Settings(BaseSettings):
13
  ALGORITHM:str
14
  JWT_SECRET_KEY:str
15
  JWT_REFRESH_SECRET_KEY:str
 
16
  # OPENAI_KEY:str
17
  APP_ID:str
18
  USER_ID:str
19
  MODEL_ID:str
20
  CLARIFAI_PAT:str
21
  MODEL_VERSION_ID:str
 
 
 
 
22
 
23
  class Config:
24
  env_file = ".env"
 
13
  ALGORITHM:str
14
  JWT_SECRET_KEY:str
15
  JWT_REFRESH_SECRET_KEY:str
16
+ JWT_VERIFICATION_SECRET_KEY:str
17
  # OPENAI_KEY:str
18
  APP_ID:str
19
  USER_ID:str
20
  MODEL_ID:str
21
  CLARIFAI_PAT:str
22
  MODEL_VERSION_ID:str
23
+
24
+ MAIL_USERNAME:str
25
+ MAIL_PASSWORD:str
26
+ MAIL_FROM:str
27
 
28
  class Config:
29
  env_file = ".env"
TechdocsAPI/backend/core/ExceptionHandlers.py CHANGED
@@ -13,6 +13,11 @@ async def handle_existing_user_found(request: Request, exec: ExistingUserExcepti
13
  content=repr(exec)
14
  )
15
 
 
 
 
 
 
16
 
17
  @app.exception_handler(InvalidCredentialsException)
18
  async def handle_login_failed(request: Request, exec: InvalidCredentialsException):
 
13
  content=repr(exec)
14
  )
15
 
16
+ @app.exception_handler(EmailNotVerifiedException)
17
+ async def email_not_verified(request: Request, exec: EmailNotVerifiedException):
18
+ return JSONResponse(status_code=status.HTTP_403_FORBIDDEN,
19
+ content=repr(exec)
20
+ )
21
 
22
  @app.exception_handler(InvalidCredentialsException)
23
  async def handle_login_failed(request: Request, exec: InvalidCredentialsException):
TechdocsAPI/backend/core/Exceptions.py CHANGED
@@ -43,3 +43,15 @@ class InfoNotFoundException(Exception):
43
 
44
  def __repr__(self):
45
  return "exception.InfoNotFoundException()"
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
  def __repr__(self):
45
  return "exception.InfoNotFoundException()"
46
+
47
+
48
+ class EmailNotVerifiedException(Exception):
49
+ def __init__(self):
50
+ self.set_statuses()
51
+ super(EmailNotVerifiedException, self).__init__()
52
+
53
+ def set_statuses(self):
54
+ self.status = 'EmailNotVerifiedException'
55
+
56
+ def __repr__(self):
57
+ return "exception.EmailNotVerifiedException()"
TechdocsAPI/backend/router.py CHANGED
@@ -1,4 +1,4 @@
1
- from fastapi import Request, Depends, UploadFile
2
  from fastapi.middleware.cors import CORSMiddleware
3
 
4
  from backend import app
@@ -42,12 +42,12 @@ def api_response_check():
42
  return response_result
43
 
44
  @app.post("/auth/signup", summary="Creates new user account", response_model=GeneralResponse, tags=["Auth Server"])
45
- async def signup(response: UserAuth):
46
  response_result = GeneralResponse.get_instance(data={},
47
  status="not_allowed",
48
  message=["Not authenticated"]
49
  )
50
- ops_signup(response_result, response)
51
 
52
  return response_result
53
 
@@ -66,3 +66,12 @@ async def inference(generate: Generate, access_token:str=Depends(JWTBearer())):
66
  user_sub=Auth.get_user_credentials(access_token)
67
 
68
  return ops_inference(generate.code_block,generate.api_key,user_sub)
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import Request, Depends, UploadFile, BackgroundTasks
2
  from fastapi.middleware.cors import CORSMiddleware
3
 
4
  from backend import app
 
42
  return response_result
43
 
44
  @app.post("/auth/signup", summary="Creates new user account", response_model=GeneralResponse, tags=["Auth Server"])
45
+ async def signup(bgtasks : BackgroundTasks, response: UserAuth):
46
  response_result = GeneralResponse.get_instance(data={},
47
  status="not_allowed",
48
  message=["Not authenticated"]
49
  )
50
+ await ops_signup(bgtasks, response_result, response)
51
 
52
  return response_result
53
 
 
66
  user_sub=Auth.get_user_credentials(access_token)
67
 
68
  return ops_inference(generate.code_block,generate.api_key,user_sub)
69
+
70
+ @app.get("/auth/verify/{token}", summary="Verify Email", response_model=GeneralResponse, tags=["Auth Server"])
71
+ async def verify_email(request: Request, token:str):
72
+ response_result = GeneralResponse.get_instance(data={},
73
+ status="not_allowed",
74
+ message=["Not authenticated"]
75
+ )
76
+
77
+ return ops_verify_email(request, response_result,token)
TechdocsAPI/backend/services/auth/ops.py CHANGED
@@ -4,12 +4,19 @@ from backend.models import *
4
  from backend.services.db.utils.DBQueries import DBQueries
5
  from backend.core.Exceptions import *
6
  from backend.core.ExceptionHandlers import *
 
7
  from backend import app
8
 
 
 
 
 
 
 
9
  # import openai
10
  # from transformers import RobertaTokenizer, T5ForConditionalGeneration
11
 
12
- def ops_signup(response_result: GeneralResponse, data: UserAuth):
13
  """Wrapper method to handle signup process.
14
 
15
  Args:
@@ -26,12 +33,31 @@ def ops_signup(response_result: GeneralResponse, data: UserAuth):
26
  if len(list(user)) != 0:
27
  # user with the entered credentials already exists
28
  raise ExistingUserException(response_result)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
- DBQueries.insert_to_database('auth', (data.username, Auth.get_password_hash(data.password), data.email),
31
- ['username', 'password', 'email'])
32
 
33
  response_result.status = 'success'
34
- response_result.message = [f'User created successfully']
35
 
36
  def ops_login(data:LoginCreds):
37
  """Wrapper method to handle login process.
@@ -50,7 +76,7 @@ def ops_login(data:LoginCreds):
50
  status="not_allowed",
51
  message=["Not authenticated"]
52
  )
53
- user = DBQueries.fetch_data_from_database('auth', ['username', 'password'], f"username='{data.username}'")
54
  user = list(user)
55
  if len(user) == 0:
56
  # user with the entered credentials does not exist
@@ -60,9 +86,12 @@ def ops_login(data:LoginCreds):
60
  # password is incorrect
61
  raise InvalidCredentialsException(response_result)
62
 
 
 
 
63
  # password is correct
64
  return TokenSchema(access_token=Auth.create_access_token(data.username),
65
- refresh_token=Auth.create_refresh_token(data.username),
66
  )
67
 
68
  def ops_regenerate_api_key(username:str) -> APIKey:
@@ -107,3 +136,33 @@ def ops_inference(source_code:str,api_key:str,username:str):
107
  return docstring
108
 
109
  return generate_docstring(source_code)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  from backend.services.db.utils.DBQueries import DBQueries
5
  from backend.core.Exceptions import *
6
  from backend.core.ExceptionHandlers import *
7
+ from backend.core.ConfigEnv import config
8
  from backend import app
9
 
10
+ from fastapi import HTTPException, BackgroundTasks
11
+ from pydantic import ValidationError
12
+ from jose import jwt
13
+
14
+ from fastapi_mail import MessageSchema, MessageType
15
+
16
  # import openai
17
  # from transformers import RobertaTokenizer, T5ForConditionalGeneration
18
 
19
+ async def ops_signup(bgtasks: BackgroundTasks, response_result: GeneralResponse, data: UserAuth):
20
  """Wrapper method to handle signup process.
21
 
22
  Args:
 
33
  if len(list(user)) != 0:
34
  # user with the entered credentials already exists
35
  raise ExistingUserException(response_result)
36
+ verifiction_token = Auth.create_access_token(f"{data.username} {data.email}", secret_name='VERIFICATION')
37
+ verification_link = f"http://localhost:8000/auth/verify/{verifiction_token}"
38
+
39
+ email_body_params = {
40
+ "username": data.username,
41
+ "verify_link": verification_link
42
+ }
43
+
44
+ message = MessageSchema(
45
+ subject="Welcome to Techdocs:[Account Verification]",
46
+ recipients=[data.email], # List of recipients, as many as you can pass
47
+ template_body=email_body_params,
48
+ subtype=MessageType.html
49
+ )
50
+
51
+ bgtasks.add_task(app.state.mail_client.send_message, message=message, template_name="email_verification.html")
52
+ # await app.state.mail_client.send_message(message=message, template_name="email_verification.html")
53
+
54
+ DBQueries.insert_to_database('auth', (data.username, Auth.get_password_hash(data.password), "", 0),
55
+ ['username', 'password', 'email', 'is_verified'])
56
+
57
 
 
 
58
 
59
  response_result.status = 'success'
60
+ response_result.message = [f'Activate your account by clicking on the link sent to {data.email}.\nMake sure to check your spam folder.']
61
 
62
  def ops_login(data:LoginCreds):
63
  """Wrapper method to handle login process.
 
76
  status="not_allowed",
77
  message=["Not authenticated"]
78
  )
79
+ user = DBQueries.fetch_data_from_database('auth', ['username', 'password', 'is_verified'], f"username='{data.username}'")
80
  user = list(user)
81
  if len(user) == 0:
82
  # user with the entered credentials does not exist
 
86
  # password is incorrect
87
  raise InvalidCredentialsException(response_result)
88
 
89
+ if not user[2]:
90
+ raise EmailNotVerifiedException()
91
+
92
  # password is correct
93
  return TokenSchema(access_token=Auth.create_access_token(data.username),
94
+ refresh_token=Auth.create_access_token(data.username, secret_name='REFRESH'),
95
  )
96
 
97
  def ops_regenerate_api_key(username:str) -> APIKey:
 
136
  return docstring
137
 
138
  return generate_docstring(source_code)
139
+
140
+
141
+ def ops_verify_email(request: Request, response_result: GeneralResponse, token:str):
142
+ try:
143
+ payload = jwt.decode(
144
+ token, config.JWT_VERIFICATION_SECRET_KEY, algorithms=[config.ALGORITHM]
145
+ )
146
+ token_data = TokenPayload(**payload)
147
+ if datetime.fromtimestamp(token_data.exp)< datetime.now():
148
+ return app.state.templates.TemplateResponse("verification_failure.html", context={"request": request})
149
+
150
+ username, email = token_data.sub.split(' ', maxsplit=1)
151
+ registered_email = DBQueries.fetch_data_from_database('auth', ['is_verified'], f"username='{username}'")
152
+ registered_email = list(registered_email)
153
+ if len(registered_email) == 0:
154
+ raise InfoNotFoundException(response_result,"User not found")
155
+ print(registered_email[0][0])
156
+ if registered_email[0][0]:
157
+ return app.state.templates.TemplateResponse("verification_failure.html", context={"request": request})
158
+
159
+
160
+ DBQueries.update_data_in_database('auth','is_verified',f"username='{username}'", (True,))
161
+ DBQueries.update_data_in_database('auth','email',f"username='{username}'", email)
162
+ response_result.status = 'success'
163
+ response_result.message = [f'Email verified successfully']
164
+ return app.state.templates.TemplateResponse("verification_success.html", context={"request": request})
165
+
166
+ except (jwt.JWTError, ValidationError):
167
+ return app.state.templates.TemplateResponse("verification_failure.html", context={"request": request})
168
+
TechdocsAPI/backend/services/auth/utils/auth_funcs.py CHANGED
@@ -16,9 +16,11 @@ from backend.core.Exceptions import *
16
  from backend.models import TokenPayload, TokenSchema
17
 
18
 
19
-
20
- ACCESS_TOKEN_EXPIRE_MINUTES = 30 # 30 minutes
21
- REFRESH_TOKEN_EXPIRE_MINUTES = 60 * 24 * 3 # 3 days
 
 
22
 
23
 
24
  class Auth:
@@ -73,7 +75,7 @@ class Auth:
73
  return entered_username == db_username
74
 
75
  @staticmethod
76
- def create_access_token(subject: Union[str, Any], expires_delta: int = None) -> str:
77
  """Creates JWT access token.
78
 
79
  Args:
@@ -83,33 +85,20 @@ class Auth:
83
  Returns:
84
  encoded_jwt: str. Encoded JWT token from the subject of interest.
85
  """
86
- if expires_delta is not None:
87
- expires_delta = datetime.utcnow() + expires_delta
88
- else:
89
- expires_delta = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
90
-
91
- to_encode = {"exp": expires_delta, "sub": str(subject)}
92
- encoded_jwt = jwt.encode(to_encode, config.JWT_SECRET_KEY, config.ALGORITHM)
93
- return encoded_jwt
94
-
95
- @staticmethod
96
- def create_refresh_token(subject: Union[str, Any], expires_delta: int = None) -> str:
97
- """Creates JWT refresh access token.
98
-
99
- Args:
100
- subject: Union[Any, str]. Hash_key to generate access token from.
101
- expires_delta: int = None. Expiry time for the JWT.
102
 
103
- Returns:
104
- encoded_jwt: str. Encoded JWT token from the subject of interest.
105
- """
106
  if expires_delta is not None:
107
  expires_delta = datetime.utcnow() + expires_delta
108
  else:
109
- expires_delta = datetime.utcnow() + timedelta(minutes=REFRESH_TOKEN_EXPIRE_MINUTES)
110
-
111
  to_encode = {"exp": expires_delta, "sub": str(subject)}
112
- encoded_jwt = jwt.encode(to_encode, config.JWT_REFRESH_SECRET_KEY, config.ALGORITHM)
113
  return encoded_jwt
114
 
115
  @staticmethod
@@ -141,9 +130,7 @@ class Auth:
141
  except (jwt.JWTError, ValidationError):
142
  raise InvalidCredentialsException(tokens)
143
  tokens['access_token'] = Auth.create_access_token(token_data.sub)
144
- tokens['refresh_token'] = Auth.create_refresh_token(token_data.sub)
145
- tokens['status'] = 'login successful'
146
- tokens['role'] = token_data.sub.split("_")[1]
147
  return tokens
148
 
149
  @classmethod
 
16
  from backend.models import TokenPayload, TokenSchema
17
 
18
 
19
+ token_expiry_info = {
20
+ 'ACCESS_TOKEN_EXPIRE_MINUTES': 30, # 30 minutes
21
+ 'REFRESH_TOKEN_EXPIRE_MINUTES': 60 * 24 * 3, # 3 days
22
+ 'VERIFICATION_TOKEN_EXPIRE_MINUTES': 20, # 20 minutes
23
+ }
24
 
25
 
26
  class Auth:
 
75
  return entered_username == db_username
76
 
77
  @staticmethod
78
+ def create_access_token(subject: Union[str, Any], expires_delta: int = None, secret_name: str = None) -> str:
79
  """Creates JWT access token.
80
 
81
  Args:
 
85
  Returns:
86
  encoded_jwt: str. Encoded JWT token from the subject of interest.
87
  """
88
+ secret_key = config.JWT_SECRET_KEY
89
+ token_expiration = token_expiry_info['ACCESS_TOKEN_EXPIRE_MINUTES']
90
+
91
+ if secret_name is not None:
92
+ secret_key = config.dict()["JWT_" + secret_name.upper() + "_SECRET_KEY"]
93
+ token_expiration = token_expiry_info[secret_name.upper() + "_TOKEN_EXPIRE_MINUTES"]
 
 
 
 
 
 
 
 
 
 
94
 
 
 
 
95
  if expires_delta is not None:
96
  expires_delta = datetime.utcnow() + expires_delta
97
  else:
98
+ expires_delta = datetime.utcnow() + timedelta(minutes=token_expiration)
99
+
100
  to_encode = {"exp": expires_delta, "sub": str(subject)}
101
+ encoded_jwt = jwt.encode(to_encode, secret_key, config.ALGORITHM)
102
  return encoded_jwt
103
 
104
  @staticmethod
 
130
  except (jwt.JWTError, ValidationError):
131
  raise InvalidCredentialsException(tokens)
132
  tokens['access_token'] = Auth.create_access_token(token_data.sub)
133
+ tokens['refresh_token'] = Auth.create_access_token(token_data.sub, secret_name='REFRESH')
 
 
134
  return tokens
135
 
136
  @classmethod
TechdocsAPI/backend/templates/email_verification.html ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Verify Email</title>
5
+ <style>
6
+ body {
7
+ font-family: Arial, sans-serif;
8
+ background-color: #f4f4f4;
9
+ margin: 0;
10
+ padding: 0;
11
+ }
12
+
13
+ .container {
14
+ width: 80%;
15
+ margin: 0 auto;
16
+ padding: 20px;
17
+ background-color: #fff;
18
+ border-radius: 8px;
19
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
20
+ }
21
+
22
+ h3 {
23
+ color: #333;
24
+ text-align: center;
25
+ }
26
+
27
+ p {
28
+ color: #555;
29
+ text-align: center;
30
+ margin-bottom: 20px;
31
+ }
32
+
33
+ a.button {
34
+ display: block;
35
+ width: 50%;
36
+ margin: 20px auto;
37
+ padding: 12px;
38
+ border-radius: 5px;
39
+ text-align: center;
40
+ text-decoration: none;
41
+ background-color: #0275d8;
42
+ color: #fff;
43
+ font-size: 1rem;
44
+ transition: background-color 0.3s;
45
+ }
46
+
47
+ a.button:hover {
48
+ background-color: #025aa5;
49
+ }
50
+
51
+ .disclaimer {
52
+ color: #777;
53
+ text-align: center;
54
+ }
55
+ </style>
56
+ </head>
57
+ <body>
58
+ <div class="container">
59
+ <h3>Account Verification</h3>
60
+
61
+ <p>Hi, {{username}}👋. Thank you for registering with Techdocs. Please click the button below to verify your account:</p>
62
+
63
+ <a class="button" href="{{verify_link}}" target="_blank">Verify your email</a>
64
+
65
+ <p class="disclaimer">Please disregard this email if you did not register with Techdocs. Thank you.</p>
66
+ </div>
67
+ </body>
68
+ </html>
TechdocsAPI/backend/templates/verification_failure.html ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
8
+ <title>Techdocs</title>
9
+ </head>
10
+ <body>
11
+
12
+ <div class="container">
13
+ <div class="row" style="margin-top: 30vh;">
14
+ <div class="col-md-10 col-sm-10 col-xm-12 m-auto p-4">
15
+ <div class="card text-center">
16
+ <div class="card-header">
17
+ Email Verification
18
+ </div>
19
+ <div class="card-body">
20
+ <h5 class="card-title">Already Verified/Link Expired</h5>
21
+ <p class="card-text">Something went wrong</p>
22
+ <button class="btn btn-secondary"><a href="https://techdocs.streamlit.app" target="_blank" style="color: white; text-decoration: none;">Login</a></button>
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </div>
28
+
29
+ <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
30
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
31
+ <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
32
+ </body>
33
+ </html>
TechdocsAPI/backend/templates/verification_success.html ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
8
+ <title>Techdocs</title>
9
+ </head>
10
+ <body>
11
+
12
+ <div class="container">
13
+ <div class="row" style="margin-top: 30vh;">
14
+ <div class="col-md-10 col-sm-10 col-xm-12 m-auto p-4">
15
+ <div class="card text-center">
16
+ <div class="card-header">
17
+ Email Verification
18
+ </div>
19
+ <div class="card-body">
20
+ <h5 class="card-title">Email Verification Successful</h5>
21
+ <p class="card-text">You can now login into you account or use or services</p>
22
+ <button class="btn btn-primary"><a href="https://techdocs.streamlit.app" target="_blank" style="color: white; text-decoration: none;">Login</a></button>
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </div>
28
+
29
+ <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
30
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
31
+ <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
32
+ </body>
33
+ </html>
TechdocsAPI/requirements.txt CHANGED
@@ -9,3 +9,4 @@ pydantic[email]
9
  langchain
10
  clarifai
11
  Pillow
 
 
9
  langchain
10
  clarifai
11
  Pillow
12
+ fastapi_mail==1.3.1
scripts/test.py CHANGED
@@ -31,19 +31,20 @@ else:
31
  cursor.execute("DROP TABLE IF EXISTS auth")
32
  cursor.execute("CREATE TABLE IF NOT EXISTS auth(username VARCHAR(15) PRIMARY KEY, password TEXT, email VARCHAR(50))")
33
  cursor.execute("CREATE TABLE IF NOT EXISTS api_key(username VARCHAR(15),apikey TEXT, FOREIGN KEY (username) REFERENCES auth(username))")
 
34
 
35
- QUERY = ('INSERT INTO {coll_name} '
36
- '(username, password, email) '
37
- 'VALUES '
38
- '(%s, %s, %s)').format(coll_name="auth")
39
 
40
- testlist=[("test2","test2","[email protected]"),("test1","test1","[email protected]")]
41
- cursor.executemany(QUERY, testlist)
42
 
43
- QUERY = ('SELECT {cols} FROM {table_name} WHERE email="[email protected]"').format(cols="*", table_name="auth")
44
- cursor.execute(QUERY)
45
- for i in cursor.fetchall():
46
- print(i)
47
 
48
 
49
 
 
31
  cursor.execute("DROP TABLE IF EXISTS auth")
32
  cursor.execute("CREATE TABLE IF NOT EXISTS auth(username VARCHAR(15) PRIMARY KEY, password TEXT, email VARCHAR(50))")
33
  cursor.execute("CREATE TABLE IF NOT EXISTS api_key(username VARCHAR(15),apikey TEXT, FOREIGN KEY (username) REFERENCES auth(username))")
34
+ cursor.execute("ALTER TABLE auth ADD is_verified BOOLEAN NOT NULL DEFAULT(false)")
35
 
36
+ # QUERY = ('INSERT INTO {coll_name} '
37
+ # '(username, password, email) '
38
+ # 'VALUES '
39
+ # '(%s, %s, %s)').format(coll_name="auth")
40
 
41
+ # testlist=[("test2","test2","[email protected]"),("test1","test1","[email protected]")]
42
+ # cursor.executemany(QUERY, testlist)
43
 
44
+ # QUERY = ('SELECT {cols} FROM {table_name} WHERE email="[email protected]"').format(cols="*", table_name="auth")
45
+ # cursor.execute(QUERY)
46
+ # for i in cursor.fetchall():
47
+ # print(i)
48
 
49
 
50