1+ import json
2+ import random
13import sys
24import os
35import argparse
46from pathlib import Path
7+ import webbrowser
8+ import http .server
9+ import socketserver
10+ import urllib .parse
11+ from threading import Thread
512
613from .commit_analyzer import CommitDocGenHook
7-
814from .folder_analyzer import FolderAnalyzerGenHook
915from .file_analyzer import FileAnalyzerGenHook
1016from .api_client import APIClient
1723penify-cli -t {token} -gf {git_folder_path}
1824"""
1925api_url = 'https://production-gateway.snorkell.ai/api'
26+ dashboard_url = "https://dashboard.penify.dev/auth/localhost/login"
27+ # api_url = 'http://localhost:8000/api'
2028
2129def install_git_hook (location , token ):
2230 """
@@ -103,6 +111,94 @@ def commit_code(gf_path: str, token: str, message: str, open_terminal: bool):
103111 sys .exit (1 )
104112 # You can add actual Git commit logic here using subprocess or GitPython, etc.
105113
114+ def save_credentials (api_key ):
115+ """
116+ Save the token and API keys in the .penify file in the user's home directory.
117+ """
118+ home_dir = Path .home ()
119+ penify_file = home_dir / '.penify'
120+
121+ credentials = {
122+ 'api_keys' : api_key
123+ }
124+
125+ try :
126+ with open (penify_file , 'w' ) as f :
127+ json .dump (credentials , f )
128+ print (f"Credentials saved successfully in { penify_file } " )
129+ except Exception as e :
130+ print (f"Error saving credentials: { str (e )} " )
131+
132+ def login ():
133+ """
134+ Open the login page in a web browser and listen for the redirect URL to capture the token.
135+ """
136+
137+ # dashboard_url = "http://localhost:8000/auth/localhost/login"
138+ redirect_port = random .randint (30000 , 50000 )
139+ redirect_url = f"http://localhost:{ redirect_port } /callback"
140+
141+ full_login_url = f"{ dashboard_url } ?redirectUri={ urllib .parse .quote (redirect_url )} "
142+
143+ print (f"Opening login page in your default web browser: { full_login_url } " )
144+ webbrowser .open (full_login_url )
145+
146+ class TokenHandler (http .server .SimpleHTTPRequestHandler ):
147+ def do_GET (self ):
148+ query = urllib .parse .urlparse (self .path ).query
149+ query_components = urllib .parse .parse_qs (query )
150+ token = query_components .get ("token" , [None ])[0 ]
151+
152+ if token :
153+ self .send_response (200 )
154+ self .send_header ("Content-type" , "text/html" )
155+ self .end_headers ()
156+ response = """
157+ <html>
158+ <body>
159+ <h1>Login Successful!</h1>
160+ <p>You can now close this window and return to the CLI.</p>
161+ </body>
162+ </html>
163+ """
164+ self .wfile .write (response .encode ())
165+ print (f"\n Login successful! Fetching API keys..." )
166+ api_key = APIClient (api_url ,None , token ).get_api_key ()
167+ if api_key :
168+ save_credentials (api_key )
169+ print ("API keys fetched and saved successfully." )
170+ else :
171+ print ("Failed to fetch API keys." )
172+ else :
173+ self .send_response (400 )
174+ self .send_header ("Content-type" , "text/html" )
175+ self .end_headers ()
176+ response = """
177+ <html>
178+ <body>
179+ <h1>Login Failed</h1>
180+ <p>Please try again.</p>
181+ </body>
182+ </html>
183+ """
184+ self .wfile .write (response .encode ())
185+ print ("\n Login failed. Please try again." )
186+
187+ # Schedule the server shutdown
188+ thread = Thread (target = self .server .shutdown )
189+ thread .daemon = True
190+ thread .start ()
191+
192+ def log_message (self , format , * args ):
193+ # Suppress log messages
194+ return
195+
196+ with socketserver .TCPServer (("" , redirect_port ), TokenHandler ) as httpd :
197+ print (f"Listening on port { redirect_port } for the redirect..." )
198+ httpd .serve_forever ()
199+
200+ print ("Login process completed. You can now use other commands with your API token." )
201+
106202def main ():
107203 parser = argparse .ArgumentParser (description = "Penify CLI tool for managing Git hooks and generating documentation." )
108204
@@ -131,6 +227,9 @@ def main():
131227 commit_parser .add_argument ("-m" , "--message" , required = False , help = "Commit message." , default = "N/A" )
132228 commit_parser .add_argument ("-e" , "--terminal" , required = False , help = "Open edit terminal" , default = "False" )
133229
230+ login_parser = subparsers .add_parser ("login" , help = "Log in to Penify and automatically obtain an API token." )
231+
232+
134233 args = parser .parse_args ()
135234
136235 if args .subcommand == "install-hook" :
@@ -142,6 +241,8 @@ def main():
142241 elif args .subcommand == "commit" :
143242 open_terminal = args .terminal .lower () == "true"
144243 commit_code (args .git_folder_path , args .token , args .message , open_terminal )
244+ elif args .subcommand == "login" :
245+ login ()
145246 else :
146247 parser .print_help ()
147248 sys .exit (1 )
0 commit comments