Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
marazt committed Apr 23, 2018
0 parents commit 11ac8d3
Show file tree
Hide file tree
Showing 26 changed files with 1,569 additions and 0 deletions.
41 changes: 41 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

#ignore thumbnails created by windows
Thumbs.db
#Ignore files build by Visual Studio
*.obj
*.exe
*.pdb
*.user
*.aps
*.pch
*.vspscc
*_i.c
*_p.c
*.ncb
*.suo
*.tlb
*.tlh
*.bak
*.cache
*.ilk
*.log
[Bb]in
[Dd]ebug*/
*.lib
*.sbr
obj/
[Rr]elease*/
_ReSharper*/
[Tt]est[Rr]esult*

.idea/
.vs/
.DS_Store
!StravaUpload.Lib/


#Ignore thumbnails created by Windows
#Ignore files built by Visual Studio
#Nuget packages folder
packages/
local.appsettings.json
21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2018 Marek Polak

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
105 changes: 105 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Strava upload

Strava Upload is s simple library to synchronize (create, update) activities on **Strava** with other activities. Currently it provides synchronization with **Suunto Movescount** moves that
are provided by [**MovescountBackup** library](https://github.com/marazt/movescount-backup).

## Version

- **Version 1.0.0** - 2018-03-15

### Getting Started/Installing

```ps
PM> Install-Package StravaUpload -Version 1.0.0
```

## Project Description

The solution consists of the following projects:

- **StravaUpload.Lib** is the main library containing `Uploader` class.

- **StravaUpload.Console** is just a sample that downloads *Movescount* data, store them on local dist and sync them with *Strava*.

- **StravaUpload.StravaUploadFunction** Azure function that periodically downloads data from *Movescount*, store them in *Azure Blob Storage* and sync them with *Strava*.

- **StravaUpload.Lib.Spec** TODO.


### Prerequisites

- .NET Core 2.0.
- For more details about *MovescountUpload* check the [project site](https://github.com/marazt/movescount-backup)

### Configuration

#### StravaUpload.Lib

- **StravaAccessToken** - Name of the member whose data we want to get.

#### StravaUpload.Console

- **MovescountAppKey** - App key to be able to query Movescount API.
- **MovescountUserKey** - User key to be able to query Movescount API.
- **MovescountUserEmail** - User email to be able to query Movescount API.
- **MovescountMemberName** - Name of the member whose data we want to get.
- **CookieValue** - A cookie value that is needed to export GPX, TCX and other move files.
This value can be get by the following steps:
1. Open console in your browser to se network requests.
1. Login into Movescount.
1. Select a requeset to `http://www.movescount.com/api/members/private/messages`.
1. Copy value of `Cookie` key in request header. It should start with `ASP.NET ...`.
- **BackupDir** - Directory where moves should be stored. Required for `FileSystemStorage`.
- **StorageConnectionString** - Connection string to Azure Blob Storage. Required for `CloudStorate`.
- **ContainerName** - Container name on Azure Blob Storage. Required for `CloudStorate`.
- **StravaAccessToken** - Strava access token wit write rights.

#### StravaUpload.StravaUploadFunction

- **MovescountAppKey** - App key to be able to query Movescount API.
- **MovescountUserKey** - User key to be able to query Movescount API.
- **MovescountUserEmail** - User email to be able to query Movescount API.
- **MovescountMemberName** - Name of the member whose data we want to get.
- **CookieValue** - A cookie value that is needed to export GPX, TCX and other move files.
This value can be get by the following steps:
1. Open console in your browser to se network requests.
1. Login into Movescount.
1. Select a requeset to `http://www.movescount.com/api/members/private/messages`.
1. Copy value of `Cookie` key in request header. It should start with `ASP.NET ...`.
- **BackupDir** - Directory where moves should be stored. Required for `FileSystemStorage`.
- **StorageConnectionString** - Connection string to Azure Blob Storage. Required for `CloudStorate`.
- **ContainerName** - Container name on Azure Blob Storage. Required for `CloudStorate`.
- **StravaAccessToken** - Strava access token wit write rights.
- **SendGridApiKey** - API key for *SendGrid* mail service to be able to send status messages.
- **EmailFrom** - Email from.
- **EmailTo** - Email to.

### StravaUpload.Lib.Uploader.cs

Uploader is the main class for activity synchronization.
It downloads activities list from **Strava**, compare them with list of moves that should be added/updated.
The first comparison is done by activity/move start/end datetime. If an acitvity is found in **Strava**, it is updated. If the activity is
not found in **Strava**, *fit*, *gpx* or other activity data file is uploaded.
It can happen that newly uploaded activity is already in **Strava**. This state is evaluated from the upload response. In this
case, the activity is just updated.

## Deployment

You can use this libraly to be run manually (`StravaUpload.Console.Program.cs`) or you can create, e.g., a *Azure function* (`StravaUpload.StravaUploadFunction.Function.cs`) or *Lambda function on AWS*, that can run periodically.

## Contributing

Any contribution is welcomed.

## Authors

- **Marek Polak** - *Initial work* - [marazt](https://github.com/marazt)

## License

© 2018 Marek Polak. This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details.

## Acknowledgments

- Enjoy it!
- If you want, you can support this project too.
46 changes: 46 additions & 0 deletions StravaUpload.Console/Configuration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using Microsoft.Extensions.Configuration;

namespace StravaUpload.Console
{

public class Configuration : MovescountBackup.Lib.IConfiguration, Lib.IConfiguration
{
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
private readonly IConfigurationRoot root;

public Configuration() { }

public Configuration(IConfigurationRoot root)
{
this.root = root;

this.MovescountAppKey = this.root["AppConfig:MovescountAppKey"];
this.MovescountUserEmail = this.root["AppConfig:MovescountUserEmail"];
this.MovescountUserKey = this.root["AppConfig:MovescountUserKey"];
this.MovescountMemberName = this.root["AppConfig:MovescountMemberName"];
this.BackupDir = this.root["AppConfig:BackupDir"];
this.CookieValue = this.root["AppConfig:CookieValue"];
this.StorageConnectionString = this.root["AppConfig:StorageConnectionString"];
this.ContainerName = this.root["AppConfig:ContainerName"];
this.StravaAccessToken = this.root["AppConfig:StravaAccessToken"];
}

public string MovescountAppKey { get; set; }

public string MovescountUserEmail { get; set; }

public string MovescountUserKey { get; set; }

public string MovescountMemberName { get; set; }

public string BackupDir { get; set; }

public string CookieValue { get; set; }

public string StorageConnectionString { get; set; }

public string ContainerName { get; set; }

public string StravaAccessToken { get; set; }
}
}
74 changes: 74 additions & 0 deletions StravaUpload.Console/ConsoleLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Logging;

namespace StravaUpload.Console
{
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public class ConsoleLogger : ILogger
{
public void Error(string message)
{
System.Console.WriteLine($"Error: {message}");
}

public void Information(string message)
{
System.Console.WriteLine($"Information: {message}");
}

public void Warning(string message)
{
System.Console.WriteLine($"warning: {message}");
}

public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
System.Console.WriteLine(state.ToString());
}

public bool IsEnabled(LogLevel logLevel)
{
throw new NotImplementedException();
}

public IDisposable BeginScope<TState>(TState state)
{
throw new NotImplementedException();
}
}

[SuppressMessage("ReSharper", "UnusedMember.Global")]
public class ConsoleLogger<T> : ILogger<T>
{
public void Error(string message)
{
System.Console.WriteLine($"Error: {message}");
}

public void Information(string message)
{
System.Console.WriteLine($"Information: {message}");
}

public void Warning(string message)
{
System.Console.WriteLine($"warning: {message}");
}

public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
System.Console.WriteLine(state.ToString());
}

public bool IsEnabled(LogLevel logLevel)
{
throw new NotImplementedException();
}

public IDisposable BeginScope<TState>(TState state)
{
throw new NotImplementedException();
}
}
}
53 changes: 53 additions & 0 deletions StravaUpload.Console/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using MovescountBackup.Lib.Services;
using Strava.Upload;
using StravaUpload.Lib;

namespace StravaUpload.Console
{
static class Program
{
// ReSharper disable once UnusedParameter.Local
static async Task Main(string[] args)
{
var configuration = SetupConfiguration();
var client = new Client(configuration, new ConsoleLogger<Client>());
var storage = new FileSystemStorage();
var downloader = new Downloader(configuration, client, storage, new ConsoleLogger<Downloader>());
var moves = await downloader.DownloadLastUserMoves(configuration.MovescountMemberName);

var uploader = new Uploader(configuration.StravaAccessToken, new ConsoleLogger<Uploader>());

var fileFormat = DataFormat.Tcx;
var movesData = moves.Select(move => (move,
Path.Combine(configuration.BackupDir, move.MoveId.ToString(), Uploader.CreateGpsFileMapName(fileFormat)),
fileFormat)).ToList();

try
{
await uploader.AddOrUpdateMovescountMovesToStravaActivities(movesData);
}
catch (Exception ex)
{
System.Console.WriteLine("Error while uploading activities");
System.Console.WriteLine(ex.Message);
System.Console.WriteLine(ex.StackTrace);
}
}


private static Configuration SetupConfiguration()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", false, true)
.AddEnvironmentVariables();
var configuration = builder.Build();
return new Configuration(configuration);
}
}
}
18 changes: 18 additions & 0 deletions StravaUpload.Console/StravaUpload.Console.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
<LangVersion>7.1</LangVersion>
</PropertyGroup>
<ItemGroup>
<None Remove="appsettings.json" />
</ItemGroup>
<ItemGroup>
<Content Include="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\StravaUpload.Lib\StravaUpload.Lib.csproj" />
</ItemGroup>
</Project>
19 changes: 19 additions & 0 deletions StravaUpload.Console/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
},
"AppConfig": {
"MovescountAppKey": "TODO",
"MovescountUserEmail": "TODO",
"MovescountUserKey": "TODO",
"MovescountMemberName": "TODO",
"CookieValue": "TODO",
"BackupDir": "TODO",
"StravaAccessToken": "TODO",
"StorageConnectionString": "TODO",
"ContainerName": "TODO"
}
}
Loading

0 comments on commit 11ac8d3

Please sign in to comment.