U
    [MhLA                     @   s   d dl Z d dlZd dlZd dlZd dlmZmZ d dlmZmZm	Z	 d dl
mZmZ d dlmZ G dd dZdd	 Zed
kre  dS )    N)datetime	timedelta)DictListOptional)create_enginetext)Pathc                   @   s   e Zd Zd'edddZedddZedd	d
ZedddZd(eedddZ	ee
dddZeedddZeeeeef dddZd)eeeeedddZee dddZd*eeed!d"d#Zd+eed$d%d&Zd S ),DynamicTokenManagertoken_manager_config.json)config_filec                 C   s(   t || _|  | _t| jd | _d S )Ndatabase_url)r	   r   load_or_create_configconfigr   engine)selfr    r   ./dynamic_token_manager.py__init__   s    

zDynamicTokenManager.__init__)returnc              
   C   s   | j  r6t| j d}t|W  5 Q R  S Q R X nNddg dddddg d	d
dddd}| | td| j   td |S dS )z(Load configuration or create default onerz7postgresql://postgres:asdf1234@localhost:5432/timesheetz&https://api-timesheet.firsteconomy.comim  ZAWToken_0   )expiry_daystoken_prefixtoken_lengthF   )Zrequire_email_verificationallowed_domainsmax_tokens_per_developer )admin_emailZsend_token_notifications)r   api_base_urlmaster_passwordstoken_settingssecuritynotificationsu   📝 Created default config: u0   🔧 Please configure the settings and run againN)r   existsopenjsonloadsave_configprint)r   fZdefault_configr   r   r   r      s,    

z)DynamicTokenManager.load_or_create_config)r   c              	   C   s,   t | jd}tj||dd W 5 Q R X dS )zSave configuration to filew   indentN)r&   r   r'   dump)r   r   r+   r   r   r   r)   4   s    zDynamicTokenManager.save_configc                 C   s<   dddddddg}t | t | t dd	d
}|S )zGenerate a new master passwordZTimeZSheetZTrackZWorkZCodeZDevZTeami'  Z04d!)secretschoiceZ	randbelow)r   Zwordspasswordr   r   r   generate_master_password9   s    &z,DynamicTokenManager.generate_master_passwordDefault)descriptionr   c                 C   s\   |   }||t  ddd}| jd | | | j td|  td|  |S )zAdd a new master passwordTr   )r4   r7   
created_atactiveusage_countr!   u#   ✅ New master password generated: u   📋 Description: )r5   r   now	isoformatr   appendr)   r*   )r   r7   r4   Zpassword_entryr   r   r   add_master_password@   s    
z'DynamicTokenManager.add_master_password)r4   r   c                 C   s^   | j d D ]N}|d |kr
|d r
|ddd |d< t  |d< | | j   dS q
d	S )
zValidate master passwordr!   r4   r9   r:   r      Z	last_usedTF)r   getr   r;   r<   r)   )r   r4   entryr   r   r   validate_master_passwordT   s    z,DynamicTokenManager.validate_master_password)developer_idr   c                 C   s2   | j d d }| j d d }| t| }|S )zGenerate API tokenr"   r   r   )r   r2   Ztoken_urlsafe)r   rC   prefixlengthtokenr   r   r   generate_api_token_   s    z&DynamicTokenManager.generate_api_token)rC   emailr   c              
   C   s>  g }|rt |dk r|d |dddd s@|d |rLd|krV|d | jd	 d
 }|r|dd  }||kr|dd|  z^| j	 J}|
tdd|i}| }| jd	 d }	||	kr|d|	 d W 5 Q R X W n4 tk
r* }
 z|d|
  W 5 d}
~
X Y nX t |dk|dS )zValidate developer information   z*Developer ID must be at least 3 characters_r   -zFDeveloper ID can only contain letters, numbers, underscore, and hyphen@zValid email is requiredr#   r   r?   z#Email domain not allowed. Allowed: z, z[SELECT COUNT(*) FROM developer_api_tokens WHERE developer_id = :dev_id AND is_active = truedev_idr   zMaximum z tokens allowed per developerzDatabase validation error: Nr   )validerrors)lenr=   replaceisalnumr   splitlowerjoinr   connectexecuter   Zscalar	Exception)r   rC   rH   rO   r   domainconnresulttoken_countZ
max_tokenser   r   r   validate_developer_infof   s2    


 "z+DynamicTokenManager.validate_developer_infoAuto-generated)rC   rH   master_passwordr7   r   c              
   C   sH  |  |sdddS | ||}|d s<dd|d dS z| |}t t| jd d d	 }| j	 2}|
td
||| d| |d |  W 5 Q R X | jd  d||dt  | | jd | jd d dd}	d||| t  d|	dW S  tk
rB }
 zdd|
 d W Y S d}
~
X Y nX dS )zCreate new developer tokenFzInvalid master passwordsuccesserrorrN   z; rO   r"   r   )Zdaysz
                        INSERT INTO developer_api_tokens 
                        (developer_id, api_token, token_name, expires_at, is_active, created_at)
                        VALUES (:dev_id, :token, :name, :expires, true, NOW())
                    z - )rM   rF   nameZexpiresr    /api/multi-devi,  r$   r   )Zapi_baseZsupport_email)api_url	api_tokenrC   Zsync_intervalZgenerated_at
expires_atZserver_infoT)rC   rg   rh   r8   )rb   
token_infoclient_configDatabase error: N)rB   r^   rU   rG   r   r;   r   r   r   rV   rW   r   commitr<   rX   )r   rC   rH   r`   r7   Z
validationrg   Zexpiry_daterZ   rj   r]   r   r   r   create_developer_token   sL    




z*DynamicTokenManager.create_developer_tokenc              
   C   s   z| j  z}|td}g }|D ]N}||d |d |d rL|d  nd|d rb|d  nd|d d q$|W  5 Q R  W S Q R X W n8 tk
r } ztd	|  g  W Y S d}~X Y nX dS )
z#List all developers with token infoa  
                        SELECT 
                            developer_id,
                            COUNT(*) as token_count,
                            MAX(created_at) as last_token_created,
                            MAX(last_used) as last_activity,
                            SUM(CASE WHEN is_active THEN 1 ELSE 0 END) as active_tokens
                        FROM developer_api_tokens 
                        GROUP BY developer_id
                        ORDER BY last_token_created DESC
                    r   r?   r-   NrI      )rC   r\   last_token_createdlast_activityactive_tokenszError listing developers: )r   rV   rW   r   r=   r<   rX   r*   )r   rZ   r[   
developersrowr]   r   r   r   list_developers   s$    
z#DynamicTokenManager.list_developersN)rC   token_idr   c              
   C   s   z| j  |}|r(|tdd|i}n2|rB|tdd|i}ndddW  5 Q R  W S |  d|jd	|j d
dW  5 Q R  W S Q R X W n6 tk
r } zdd| d W Y S d}~X Y nX dS )z/Revoke tokens for a developer or specific tokenzJUPDATE developer_api_tokens SET is_active = false WHERE api_token = :tokenrF   zNUPDATE developer_api_tokens SET is_active = false WHERE developer_id = :dev_idrM   Fz(Either developer_id or token_id requiredra   TzRevoked z tokens)rb   Zrevoked_countmessagerk   N)r   rV   rW   r   rl   ZrowcountrX   )r   rC   ru   rZ   r[   r]   r   r   r   revoke_tokens   s(    z!DynamicTokenManager.revoke_tokens)custom_api_urlr   c                 C   s2   |p| j d  d}dt   d| d}|S )z4Generate installer script with current configurationr    re   zA#!/bin/bash
# Dynamic Activity Tracker Installer
# Generated at: z

set -e

API_URL="uu  "
INSTALL_DIR="$HOME/.timesheet-tracker"

echo "🚀 Installing Timesheet Activity Tracker..."

# [Rest of installer script with dynamic API_URL]
# This would contain the full installer script from before
# but with the API_URL dynamically set

echo "Configuration:"
echo "  API URL: $API_URL"
echo "  Install Directory: $INSTALL_DIR"

# ... rest of installation logic ...
)r   r   r;   r<   )r   rx   rf   Zinstaller_templater   r   r   get_installer_script  s    
z(DynamicTokenManager.get_installer_script)r   )r6   )r_   )NN)N)__name__
__module____qualname__strr   r   r   r)   r5   r>   boolrB   rG   r^   rm   r   rt   rw   ry   r   r   r   r   r
      s   !(>"r
   c               	   C   s&  ddl } | jdd}|jddddd	d
dgd |jddd |jddd |jddd |jddd |jdddd | }t|j}|jdkrttd td td|jd  d	 }|r||jd< td|jd   d	 }|r||jd < td!	 }|r||jd" d#< td$	 }|rDd%d& |
d'D |jd( d)< ||j |d*}td+ td,|  n|jdkr|jptd-}	||	}td.|  nv|jdkr|jptd/}
|jptd0}|jptd1}|jpd2}	||
|||	}|d3 rtd4 td5|d6 d7   td8|d6 d9   td:|d6 d;   d<|
 d=}t|d>}tj|d? |d@dA W 5 Q R X tdB|  ntdC|dD   nn|jd	krV| }|stdE dS tdF tdG |D ]d}tdH|d7   tdI|dJ  dK|dL   tdM|dN   tdO|dP pBdQ  t  qn|jd
kr|jpptdR}
|
r|j|
dS}n.tdT}| dUkrtdV dS tdW dS |d3 rtdX|dY   ntdC|dD   n<|jdkr"| }tdZd>}|| W 5 Q R X td[ dS )\z"CLI interface for token managementr   NzDynamic Token Manager)r7   actionZsetupzadd-master-passwordzcreate-tokenzlist-developerszrevoke-tokenszgenerate-installer)choicesz--developer-idzDeveloper ID)helpz--emailzDeveloper emailz--master-passwordzMaster passwordz--descriptionzToken descriptionz--configr   zConfig file path)defaultr   u   🔧 Token Manager Setupz==============================zDatabase URL [r   z]: zAPI Base URL [r    zAdmin email (optional): r$   r   z8Allowed email domains (comma-separated, empty for all): c                 S   s   g | ]}|  qS r   )strip).0dr   r   r   
<listcomp>P  s     zmain.<locals>.<listcomp>,r#   r   zInitial setupu   
✅ Setup complete!u0   📋 Share this master password with your team: zDescription for this password: zNew master password: zDeveloper ID: zEmail: zMaster password: zCLI generatedrb   u   ✅ Token created successfully!zDeveloper: ri   rC   zToken: rg   z	Expires: rh   Zconfig_z.jsonr,   rj   r-   r.   u   📁 Config saved to: u   ❌ Error: rc   zNo developers foundu   👥 Developers:zP--------------------------------------------------------------------------------zID: z  Active Tokens: rq   /r\   z  Last Token: ro   z  Last Activity: rp   ZNeverz1Developer ID to revoke (or press Enter for all): )rC   zRevoke ALL tokens? (yes/no): Zyesz#Bulk revocation not implemented yetZ	Cancelledu   ✅ rv   zinstall_timesheet_tracker.shu<   ✅ Installer script generated: install_timesheet_tracker.sh)argparseArgumentParseradd_argument
parse_argsr
   r   r   r*   inputr   rS   r)   r>   r7   rC   rH   r`   rm   r&   r'   r0   rt   rw   rT   ry   write)r   parserargsZmanagerZdb_urlrf   r   Zdomainsr4   r7   rC   rH   r`   r[   r   r+   rr   ZdevZconfirmZscriptr   r   r   main'  s        






r   __main__)osr'   r2   Zhashlibr   r   typingr   r   r   Z
sqlalchemyr   r   pathlibr	   r
   r   rz   r   r   r   r   <module>   s     z