U
    [Mh7                     @   s  d dl mZmZmZmZmZmZ d dlmZ d dl	m
Z
mZmZmZ d dlmZmZmZ d dlZd dlmZ d dlZd dlZd dlZd dlmZ d dlZe ZeeZG dd	 d	eZG d
d deZG dd deZ d'e!e!e!dddZ"d(e!e!e!e#dddZ$e%dedddedeefee!e!edddZ&e%dedddedeefee!e!edddZ'e(dedd deefe!e!ed!d"d#Z)e(d$d%d& Z*dS ))    )	APIRouterDependsHTTPExceptionstatusHeaderRequest)Session)ListDictOptionalAny)datetimetimezone	timedeltaN)	BaseModel)get_dbc                   @   s.   e Zd ZU eed< eed< eeef ed< dS )ActivityWatchEvent	timestampdurationdataN)__name__
__module____qualname__str__annotations__floatr
   r    r   r   ./activitywatch_webhook.pyr      s   
r   c                   @   s2   e Zd ZU eed< eed< eed< ee ed< dS )ActivityWatchBucketidtypehostnameZeventsN)r   r   r   r   r   r	   r   r   r   r   r   r      s   
r   c                   @   s2   e Zd ZU ee ed< eeef ed< eed< dS )ActivityWatchWebhookZbucketsZ
timeperiodr!   N)r   r   r   r	   r   r   r
   r   r   r   r   r   r"      s   
r"    )app_namewindow_titlereturnc                    s   | sdS |    |r|  nd}t fdddD r:dS t fdddD rTd	S t fd
ddD rndS t fdddD rdS t fdddD rdS t fdddD rdS dS )z5Categorize application based on name and window titleotherr#   c                 3   s   | ]}| kV  qd S Nr   .0browserapp_name_lowerr   r   	<genexpr>'   s     z)categorize_application.<locals>.<genexpr>)chromefirefoxsafariedgeZoperaZbraver+   c                 3   s   | ]}| kV  qd S r(   r   r*   Zider,   r   r   r.   +   s     )vscodezvisual studiopycharmintellijZsublimeZatomZvimZemacsz	notepad++cursorcodeZdevelopmentc                 3   s   | ]}| kV  qd S r(   r   )r*   dbr,   r   r   r.   /   s     )ZdatagripZpgadminZmysqlZdbeaverZnavicatZ	sqlserverZoracledatabasec                 3   s   | ]}| kV  qd S r(   r   )r*   Zprodr,   r   r   r.   3   s     )ZwordZexcelZ
powerpointZoutlookZteamsZslackZdiscordZzoomZnotionZobsidianZpostmanZproductivityc                 3   s   | ]}| kV  qd S r(   r   )r*   Zmediar,   r   r   r.   7   s     )ZspotifyZyoutubeZvlczmedia playerZnetflixZtwitchZentertainmentc                 3   s   | ]}| kV  qd S r(   r   )r*   systemr,   r   r   r.   ;   s     )	ZexplorerfinderZterminalcmdZ
powershellztask managerlockZdwmZwinlogonr;   )lowerany)r$   r%   window_title_lowerr   r,   r   categorize_application   s"    rB   )r%   r$   urlr&   c              	      s   ddd|dd}| s|s|S |r(|  nd | r8|   nd}t fdddD rd| kr| d}t|d	kr|d
  }|d  }||dd|kr| d| n|d| d| d |S nt fdddD r|rzd
dlm} ||}	|	j	dddksdkrH|d|	j
p,d dd|  d |W S dddd d!d"g}
tfd#d|
D r|d$d%|  d |W S W n tk
r   Y nX d| kr| dd
  }||d&d'| d |S |r|	d(dnd)}||d| r| d*|  n|d |S )+z@Extract project information from window title, app name, and URLNZWork)project_nameproject_type	file_pathrC   detailed_activityr#   c                 3   s   | ]}| kV  qd S r(   r   r3   r,   r   r   r.   Q   s     z'extract_project_info.<locals>.<genexpr>)r7   r4   r8   r5   r6   z -    r      ZDevelopment./zCoding: z in )rD   rE   rF   rG   c                 3   s   | ]}| kV  qd S r(   r   r)   r,   r   r   r.   b   s     )r/   r0   r2   r1   )urlparsezwww.Z	localhostz	127.0.0.1z
localhost:Z3000zWeb DevelopmentzLocal Development: )rD   rE   rG   z
github.comzstackoverflow.comzdocs.zapi.z
developer.zconsole.c                 3   s   | ]}| kV  qd S r(   r   )r*   Zwork_domain)domainr   r   r.   u   s     zWeb Researchz
Research: zWeb Browsingz
Browsing: z.exeUnknownz: )r?   r@   splitlenstripupdateZurllib.parserL   ZnetlocreplaceZport	Exception)r%   r$   rC   project_inforA   partsfilenameZprojectrL   ZparsedZwork_domainsZ
page_titleZclean_app_namer   )r-   rM   r   extract_project_info@   sz    


rX   z/activitywatch/webhook.zDeveloper-ID)aliasrequestdeveloper_idauthorizationr9   c                    s  | dstddd|dd }|tjtjj|ktjj|ktjj	dk
 }|sftdddz|  I d	H }td
|  d}| D ]\}}	t|	tr|	D ]v}
t|
tsq|
d}|
dd}|
di }|r|dk rqzt|dd}|dp|dd}|dd}|dd	}|rB|dkrFW qt||}t|||}|tjtjj|ktjj|ktjj|ktjj|k
 }|rW qtj|||||d ||||d |d |d d}|| |d7 }W q tk
r" } ztd|  W Y qW 5 d	}~X Y qX qqtt j!|_"|#  td| d|j$  d d!| d"||j$d#W S  tj%k
r   td$d%dY nR tk
r } z2|&  td&|  td'd(t'| dW 5 d	}~X Y nX d	S ))z&Receive ActivityWatch data via webhookzBearer   zInvalid authorization headerZstatus_codeZdetail rI   TzInvalid developer or tokenNz$Received ActivityWatch webhook from r   r   r   r      Zz+00:00ZappZapplicationrN   titler#   rC   rF   rD   rE   rG   )r\   application_namer%   rC   rF   categoryr   r   rD   rE   rG   zError processing event: zSuccessfully processed z activities from successz
Processed z activities)r   messager\   developer_namei  zInvalid JSON dataz(Error processing ActivityWatch webhook: i  zProcessing error: )(
startswithr   rO   querymodels	Developerfilterr\   	api_tokenactivefirstjsonloggerinfoitems
isinstancelistdictgetr   ZfromisoformatrS   rB   rX   ZActivityRecordr   rd   r   addrT   errornowr   utcZ	last_syncZcommitnameZJSONDecodeErrorZrollbackr   )r[   r\   r]   r9   token	developerZwebhook_dataZprocessed_activitiesZbucket_nameZbucket_dataZeventZtimestamp_strr   r   r   r$   r%   rC   re   rU   existingZactivity_recorder   r   r   receive_activitywatch_webhook   s    















r   z/activitywatch/syncc                    s   t | |||I dH S )z0Alternative sync endpoint for ActivityWatch dataN)r   rZ   r   r   r   receive_activitywatch_sync  s    
r   z$/activitywatch/config/{developer_id}zAdmin-Token)r\   admin_tokenr9   c                    s   ddl }|dd}||kr(tddd|tjtjj| ktjjdk	 }|s`td	d
dddl }|d|dd}d|j
 d| d|j d|j d| d|j d|j d}| |j
|dddddS )z2Generate ActivityWatch config.toml for a developerr   NZADMIN_TOKENz!timesheet-admin-2025-secure-tokenr^   zAdmin access requiredr_   Ti  zDeveloper not foundZ
SERVER_URLZFRONTEND_URLz!https://your-timesheet-server.comz"# ActivityWatch Configuration for as  
# Place this file in your ActivityWatch config directory
# Windows: %APPDATA%\activitywatch\aw-server\config.toml
# Linux: ~/.config/activitywatch/aw-server/config.toml
# macOS: ~/Library/Application Support/activitywatch/aw-server/config.toml

[server]
host = "127.0.0.1"
port = 5600

# Team timesheet integration
[integrations.timesheet]
enabled = true
webhook_url = "z//api/v1/activitywatch/webhook"
developer_id = "z"
api_token = "z"
sync_interval = 1800  # 30 minutes in seconds

# Webhook configuration
[webhooks]
enabled = true

[[webhooks.endpoints]]
url = "zo/api/v1/activitywatch/webhook"
method = "POST"
interval = 1800  # 30 minutes
headers = {
    "Developer-ID" = "z!",
    "Authorization" = "Bearer a  ",
    "Content-Type" = "application/json"
}

# Include these buckets in sync
include_buckets = [
    "aw-watcher-window",
    "aw-watcher-web-chrome", 
    "aw-watcher-web-firefox",
    "aw-watcher-afk"
]

# Privacy settings
[privacy]
include_window_titles = true
include_urls = true
exclude_patterns = [
    "*password*",
    "*login*", 
    "*private*",
    "*confidential*"
]

# Logging
[logging]
level = "INFO"
z-%APPDATA%\activitywatch\aw-server\config.tomlz-~/.config/activitywatch/aw-server/config.tomlzA~/Library/Application Support/activitywatch/aw-server/config.toml)ZwindowsZlinuxZmacos)r\   rh   config_tomlZinstallation_instructions)osgetenvr   rj   rk   rl   rm   r\   ro   rp   r}   rn   )r\   r   r9   r   Zexpected_admin_tokenr   Z
server_urlr   r   r   r   get_activitywatch_config  sB    	


9r   z/activitywatch/test-webhookc                      s   ddt tj dS )z'Test endpoint for ActivityWatch webhookZhealthyz)ActivityWatch webhook endpoint is working)r   rg   r   )r   r{   r   r|   Z	isoformatr   r   r   r   test_webhook_endpointw  s    r   )r#   )N)+Zfastapir   r   r   r   r   r   Zsqlalchemy.ormr   typingr	   r
   r   r   r   r   r   rq   Zpydanticr   rk   ZschemasZcrudr:   r   ZloggingZrouterZ	getLoggerr   rr   r   r   r"   r   rB   rw   rX   Zpostr   r   rx   r   r   r   r   r   r   <module>   sZ    
"T
w

^