<s> from tapiriik . settings import WEB_ROOT , HTTP_SOURCE_ADDR <EOL> from tapiriik . services . service_base import ServiceAuthenticationType , ServiceBase <EOL> from tapiriik . services . interchange import UploadedActivity , ActivityType , ActivityStatistic , ActivityStatisticUnit , Waypoint , Location , Lap <EOL> from tapiriik . services . api import APIException , APIWarning , UserException , UserExceptionType <EOL> from tapiriik . services . sessioncache import SessionCache <EOL> from tapiriik . payments import ExternalPaymentProvider <EOL> from django . core . urlresolvers import reverse <EOL> from datetime import datetime , timedelta <EOL> import requests <EOL> import logging <EOL> import time <EOL> import json <EOL> import tempfile <EOL> logger = logging . getLogger ( __name__ ) <EOL> class MotivatoService ( ServiceBase ) : <EOL> ID = "<STR_LIT>" <EOL> DisplayName = "<STR_LIT>" <EOL> DisplayAbbreviation = "<STR_LIT>" <EOL> AuthenticationType = ServiceAuthenticationType . UsernamePassword <EOL> RequiresExtendedAuthorizationDetails = True <EOL> _activityMappings = { <EOL> ActivityType . Running : <NUM_LIT:1> , <EOL> ActivityType . Cycling : <NUM_LIT:2> , <EOL> ActivityType . MountainBiking : <NUM_LIT:2> , <EOL> ActivityType . Walking : <NUM_LIT:7> , <EOL> ActivityType . Hiking : <NUM_LIT:7> , <EOL> ActivityType . DownhillSkiing : <NUM_LIT:5> , <EOL> ActivityType . CrossCountrySkiing : <NUM_LIT:5> , <EOL> ActivityType . Snowboarding : <NUM_LIT:5> , <EOL> ActivityType . Skating : <NUM_LIT:5> , <EOL> ActivityType . Swimming : <NUM_LIT:3> , <EOL> ActivityType . Wheelchair : <NUM_LIT:5> , <EOL> ActivityType . Rowing : <NUM_LIT:5> , <EOL> ActivityType . Elliptical : <NUM_LIT:5> , <EOL> ActivityType . Gym : <NUM_LIT:4> , <EOL> ActivityType . Climbing : <NUM_LIT:5> , <EOL> ActivityType . Other : <NUM_LIT:5> , <EOL> } <EOL> _reverseActivityMappings = { <EOL> <NUM_LIT:1> : ActivityType . Running , <EOL> <NUM_LIT:2> : ActivityType . Cycling , <EOL> <NUM_LIT:3> : ActivityType . Swimming , <EOL> <NUM_LIT:4> : ActivityType . Gym , <EOL> <NUM_LIT:5> : ActivityType . Other , <EOL> <NUM_LIT:6> : ActivityType . Other , <EOL> <NUM_LIT:7> : ActivityType . Walking <EOL> } <EOL> SupportedActivities = list ( _reverseActivityMappings . values ( ) ) <EOL> _sessionCache = SessionCache ( "<STR_LIT>" , lifetime = timedelta ( minutes = <NUM_LIT:30> ) , freshen_on_get = True ) <EOL> _obligatory_headers = { <EOL> "<STR_LIT>" : "<STR_LIT>" <EOL> } <EOL> _urlRoot = "<STR_LIT>" <EOL> def __init__ ( self ) : <EOL> rate_lock_path = tempfile . gettempdir ( ) + "<STR_LIT>" % HTTP_SOURCE_ADDR <EOL> open ( rate_lock_path , "<STR_LIT:a>" ) . close ( ) <EOL> self . _rate_lock = open ( rate_lock_path , "<STR_LIT>" ) <EOL> def WebInit ( self ) : <EOL> self . UserAuthorizationURL = WEB_ROOT + reverse ( "<STR_LIT>" , kwargs = { "<STR_LIT>" : self . ID } ) <EOL> def _getPaymentState ( self , serviceRecord ) : <EOL> session = self . _get_session ( record = serviceRecord ) <EOL> self . _rate_limit ( ) <EOL> return session . get ( self . _urlRoot + "<STR_LIT>" ) . json ( ) [ "<STR_LIT>" ] <EOL> def _applyPaymentState ( self , serviceRecord ) : <EOL> from tapiriik . auth import User <EOL> state = self . _getPaymentState ( serviceRecord ) <EOL> ExternalPaymentProvider . FromID ( "<STR_LIT>" ) . ApplyPaymentState ( User . GetByConnection ( serviceRecord ) , state , serviceRecord . ExternalID , duration = None ) <EOL> def Authorize ( self , email , password ) : <EOL> from tapiriik . auth . credential_storage import CredentialStore <EOL> session = self . _get_session ( email = email , password = password ) <EOL> self . _rate_limit ( ) <EOL> id = session . get ( self . _urlRoot + "<STR_LIT>" ) . json ( ) [ "<STR_LIT:id>" ] <EOL> if not len ( id ) : <EOL> raise APIException ( "<STR_LIT>" , block = True , user_exception = UserException ( UserExceptionType . Authorization , intervention_required = True ) ) <EOL> return ( id , { } , { "<STR_LIT>" : CredentialStore . Encrypt ( email ) , "<STR_LIT>" : CredentialStore . Encrypt ( password ) } ) <EOL> def UploadActivity ( self , serviceRecord , activity ) : <EOL> logger . debug ( "<STR_LIT>" ) <EOL> session = self . _get_session ( record = serviceRecord ) <EOL> dic = dict ( <EOL> training_at = activity . StartTime . strftime ( "<STR_LIT>" ) , <EOL> distance = activity . Stats . Distance . asUnits ( ActivityStatisticUnit . Kilometers ) . Value , <EOL> duration = "<STR_LIT>" , <EOL> user_comment = activity . Notes , <EOL> updated_at = datetime . now ( ) . strftime ( "<STR_LIT>" ) , <EOL> created_at = activity . StartTime . strftime ( "<STR_LIT>" ) , <EOL> discipline_id = self . _activityMappings [ activity . Type ] , <EOL> source_id = <NUM_LIT:8> , <EOL> metas = dict ( <EOL> distance = activity . Stats . Distance . asUnits ( ActivityStatisticUnit . Kilometers ) . Value , <EOL> duration = "<STR_LIT>" , <EOL> time_start = activity . StartTime . strftime ( "<STR_LIT>" ) <EOL> ) , <EOL> track = { } <EOL> ) <EOL> if activity . Stats . TimerTime . Value is not None : <EOL> secs = activity . Stats . TimerTime . asUnits ( ActivityStatisticUnit . Seconds ) . Value <EOL> elif activity . Stats . MovingTime . Value is not None : <EOL> secs = activity . Stats . MovingTime . asUnits ( ActivityStatisticUnit . Seconds ) . Value <EOL> else : <EOL> secs = ( activity . EndTime - activity . StartTime ) . total_seconds ( ) <EOL> dic [ "<STR_LIT>" ] [ "<STR_LIT>" ] = str ( timedelta ( seconds = secs ) ) <EOL> dic [ "<STR_LIT>" ] = str ( timedelta ( seconds = secs ) ) <EOL> pace = str ( timedelta ( seconds = secs / activity . Stats . Distance . Value ) ) <EOL> meta_hr_avg = activity . Stats . HR . Average <EOL> meta_hr_max = activity . Stats . HR . Max <EOL> if pace : <EOL> dic [ "<STR_LIT>" ] [ "<STR_LIT>" ] = pace <EOL> if meta_hr_avg : <EOL> dic [ "<STR_LIT>" ] [ "<STR_LIT>" ] = meta_hr_avg <EOL> if meta_hr_max : <EOL> dic [ "<STR_LIT>" ] [ "<STR_LIT>" ] = meta_hr_max <EOL> if len ( activity . Laps ) > <NUM_LIT:0> : <EOL> dic [ "<STR_LIT>" ] = dict ( <EOL> name = activity . Name , <EOL> mtime = secs , <EOL> points = [ ] <EOL> ) <EOL> for tk in activity . Laps : <EOL> for wpt in tk . Waypoints : <EOL> pt = dict ( <EOL> lat = wpt . Location . Latitude , <EOL> lon = wpt . Location . Longitude , <EOL> ele = wpt . Location . Altitude , <EOL> bpm = wpt . HR , <EOL> moment = wpt . Timestamp . strftime ( '<STR_LIT>' ) <EOL> ) <EOL> if wpt . Speed and wpt . Speed != None and wpt . Speed != <NUM_LIT:0> : <EOL> pt [ "<STR_LIT>" ] = ( <NUM_LIT> / wpt . Speed ) <EOL> dic [ "<STR_LIT>" ] [ "<STR_LIT>" ] . append ( pt ) <EOL> toSend = json . dumps ( dic ) <EOL> try : <EOL> res = session . post ( self . _urlRoot + "<STR_LIT>" , data = toSend ) <EOL> except APIWarning as e : <EOL> raise APIException ( str ( e ) ) <EOL> if res . status_code != <NUM_LIT> : <EOL> raise APIException ( "<STR_LIT>" % ( res . status_code , res . text ) ) <EOL> try : <EOL> retJson = res . json ( ) <EOL> except ValueError : <EOL> raise APIException ( "<STR_LIT>" % ( res . status_code , res . text ) ) <EOL> return retJson [ "<STR_LIT:id>" ] <EOL> def _parseDate ( self , date ) : <EOL> return datetime . strptime ( date , "<STR_LIT>" ) <EOL> def _parseDateTime ( self , date ) : <EOL> try : <EOL> return datetime . strptime ( date , "<STR_LIT>" ) <EOL> except ValueError : <EOL> return datetime . strptime ( date , "<STR_LIT>" ) <EOL> def _durationToSeconds ( self , dur ) : <EOL> parts = dur . split ( "<STR_LIT::>" ) <EOL> return int ( parts [ <NUM_LIT:0> ] ) * <NUM_LIT> + int ( parts [ <NUM_LIT:1> ] ) * <NUM_LIT> + int ( parts [ <NUM_LIT:2> ] ) <EOL> def DownloadActivityList ( self , serviceRecord , exhaustive = False ) : <EOL> logger . debug ( "<STR_LIT>" ) <EOL> self . _applyPaymentState ( serviceRecord ) <EOL> logger . debug ( "<STR_LIT>" ) <EOL> session = self . _get_session ( record = serviceRecord ) <EOL> activities = [ ] <EOL> exclusions = [ ] <EOL> self . _rate_limit ( ) <EOL> retried_auth = False <EOL> headers = { } <EOL> res = session . post ( self . _urlRoot + "<STR_LIT>" , headers = headers ) <EOL> if res . status_code == <NUM_LIT> and not retried_auth : <EOL> retried_auth = True <EOL> session = self . _get_session ( serviceRecord , skip_cache = True ) <EOL> try : <EOL> respList = res . json ( ) ; <EOL> except ValueError : <EOL> res_txt = res . text <EOL> raise APIException ( "<STR_LIT>" % res . status_code ) <EOL> for actInfo in respList : <EOL> if "<STR_LIT>" in actInfo : <EOL> duration = self . _durationToSeconds ( actInfo [ "<STR_LIT>" ] ) <EOL> else : <EOL> continue <EOL> activity = UploadedActivity ( ) <EOL> if "<STR_LIT>" in actInfo [ "<STR_LIT>" ] : <EOL> startTimeStr = actInfo [ "<STR_LIT>" ] + "<STR_LIT:U+0020>" + actInfo [ "<STR_LIT>" ] [ "<STR_LIT>" ] <EOL> else : <EOL> startTimeStr = actInfo [ "<STR_LIT>" ] + "<STR_LIT>" <EOL> activity . StartTime = self . _parseDateTime ( startTimeStr ) <EOL> activity . EndTime = self . _parseDateTime ( startTimeStr ) + timedelta ( seconds = duration ) <EOL> activity . Type = self . _reverseActivityMappings [ actInfo [ "<STR_LIT>" ] ] <EOL> activity . Stats . TimerTime = ActivityStatistic ( ActivityStatisticUnit . Seconds , value = duration ) <EOL> if "<STR_LIT>" in actInfo : <EOL> activity . Stats . Distance = ActivityStatistic ( ActivityStatisticUnit . Kilometers , value = float ( actInfo [ "<STR_LIT>" ] ) ) <EOL> activity . ServiceData = { "<STR_LIT>" : int ( actInfo [ "<STR_LIT:id>" ] ) } <EOL> activity . CalculateUID ( ) <EOL> logger . debug ( "<STR_LIT>" % activity . UID ) <EOL> activities . append ( activity ) <EOL> return activities , exclusions <EOL> def DownloadActivity ( self , serviceRecord , activity ) : <EOL> workoutID = activity . ServiceData [ "<STR_LIT>" ] <EOL> logger . debug ( "<STR_LIT>" % workoutID ) ; <EOL> session = self . _get_session ( record = serviceRecord ) <EOL> resp = session . get ( self . _urlRoot + "<STR_LIT>" % workoutID ) <EOL> try : <EOL> res = resp . json ( ) <EOL> except ValueError : <EOL> raise APIException ( "<STR_LIT>" % ( workoutID , res . text ) ) <EOL> lap = Lap ( stats = activity . Stats , startTime = activity . StartTime , endTime = activity . EndTime ) <EOL> activity . Laps = [ lap ] <EOL> activity . GPS = False <EOL> if "<STR_LIT>" in res and "<STR_LIT>" in res [ "<STR_LIT>" ] : <EOL> for pt in res [ "<STR_LIT>" ] [ "<STR_LIT>" ] : <EOL> wp = Waypoint ( ) <EOL> if "<STR_LIT>" not in pt : <EOL> continue <EOL> wp . Timestamp = self . _parseDateTime ( pt [ "<STR_LIT>" ] ) <EOL> if ( "<STR_LIT>" in pt and "<STR_LIT>" in pt ) or "<STR_LIT>" in pt : <EOL> wp . Location = Location ( ) <EOL> if "<STR_LIT>" in pt and "<STR_LIT>" in pt : <EOL> wp . Location . Latitude = pt [ "<STR_LIT>" ] <EOL> wp . Location . Longitude = pt [ "<STR_LIT>" ] <EOL> activity . GPS = True <EOL> if "<STR_LIT>" in pt : <EOL> wp . Location . Altitude = float ( pt [ "<STR_LIT>" ] ) <EOL> if "<STR_LIT>" in pt : <EOL> wp . HR = pt [ "<STR_LIT>" ] <EOL> lap . Waypoints . append ( wp ) <EOL> activity . Stationary = len ( lap . Waypoints ) == <NUM_LIT:0> <EOL> return activity <EOL> def _get_session ( self , record = None , email = None , password = None , skip_cache = False ) : <EOL> from tapiriik . auth . credential_storage import CredentialStore <EOL> cached = self . _sessionCache . Get ( record . ExternalID if record else email ) <EOL> if cached and not skip_cache : <EOL> return cached <EOL> if record : <EOL> password = CredentialStore . Decrypt ( record . ExtendedAuthorization [ "<STR_LIT>" ] ) <EOL> email = CredentialStore . Decrypt ( record . ExtendedAuthorization [ "<STR_LIT>" ] ) <EOL> session = requests . Session ( ) <EOL> self . _rate_limit ( ) <EOL> mPreResp = session . get ( self . _urlRoot + "<STR_LIT>" , allow_redirects = False ) <EOL> if mPreResp . status_code == <NUM_LIT> : <EOL> data = { <EOL> "<STR_LIT>" : email , <EOL> "<STR_LIT>" : password , <EOL> "<STR_LIT>" : "<STR_LIT:true>" , <EOL> } <EOL> preResp = session . post ( self . _urlRoot + "<STR_LIT>" , data = data ) <EOL> if preResp . status_code != <NUM_LIT:200> : <EOL> raise APIException ( "<STR_LIT>" % ( preResp . status_code , preResp . text ) ) <EOL> try : <EOL> preResp = preResp . json ( ) <EOL> except ValueError : <EOL> raise APIException ( "<STR_LIT>" % ( preResp . status_code , preResp . text ) , block = True , user_exception = UserException ( UserExceptionType . Authorization , intervention_required = True ) ) <EOL> if "<STR_LIT:success>" not in preResp and "<STR_LIT:error>" not in preResp : <EOL> raise APIException ( "<STR_LIT>" , block = True , user_exception = UserException ( UserExceptionType . Authorization , intervention_required = True ) ) <EOL> success = True <EOL> error = "<STR_LIT>" <EOL> if "<STR_LIT:success>" in preResp : <EOL> success = [ "<STR_LIT:success>" ] <EOL> if "<STR_LIT:error>" in preResp : <EOL> error = preResp [ "<STR_LIT:error>" ] <EOL> if not success : <EOL> logger . debug ( "<STR_LIT>" % ( error ) ) <EOL> raise APIException ( "<STR_LIT>" , block = True , user_exception = UserException ( UserExceptionType . Authorization , intervention_required = True ) ) <EOL> self . _rate_limit ( ) <EOL> mRedeemResp1 = session . get ( self . _urlRoot + "<STR_LIT>" , allow_redirects = False ) <EOL> if mRedeemResp1 . status_code != <NUM_LIT:200> : <EOL> raise APIException ( "<STR_LIT>" % ( mRedeemResp1 . status_code , mRedeemResp1 . text ) ) <EOL> else : <EOL> logger . debug ( "<STR_LIT>" % mPreResp . status_code ) <EOL> raise APIException ( "<STR_LIT>" % ( mPreResp . status_code , mPreResp . text ) ) <EOL> self . _sessionCache . Set ( record . ExternalID if record else email , session ) <EOL> session . headers . update ( self . _obligatory_headers ) <EOL> return session <EOL> def _rate_limit ( self ) : <EOL> import fcntl , time <EOL> min_period = <NUM_LIT:1> <EOL> print ( "<STR_LIT>" ) <EOL> fcntl . flock ( self . _rate_lock , fcntl . LOCK_EX ) <EOL> try : <EOL> print ( "<STR_LIT>" ) <EOL> self . _rate_lock . seek ( <NUM_LIT:0> ) <EOL> last_req_start = self . _rate_lock . read ( ) <EOL> if not last_req_start : <EOL> last_req_start = <NUM_LIT:0> <EOL> else : <EOL> last_req_start = float ( last_req_start ) <EOL> wait_time = max ( <NUM_LIT:0> , min_period - ( time . time ( ) - last_req_start ) ) <EOL> time . sleep ( wait_time ) <EOL> self . _rate_lock . seek ( <NUM_LIT:0> ) <EOL> self . _rate_lock . write ( str ( time . time ( ) ) ) <EOL> self . _rate_lock . flush ( ) <EOL> print ( "<STR_LIT>" % wait_time ) <EOL> finally : <EOL> fcntl . flock ( self . _rate_lock , fcntl . LOCK_UN ) <EOL> def DeleteCachedData ( self , serviceRecord ) : <EOL> pass <EOL> def RevokeAuthorization ( self , serviceRecord ) : <EOL> pass </s>
