actual initial
This commit is contained in:
parent
612632b0c1
commit
7cc8155b5b
1
.gitignore
vendored
1
.gitignore
vendored
@ -398,3 +398,4 @@ FodyWeavers.xsd
|
||||
# JetBrains Rider
|
||||
*.sln.iml
|
||||
|
||||
appsettings.json
|
||||
|
11
Configuration.cs
Normal file
11
Configuration.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ttrss_co_client
|
||||
{
|
||||
public class Configuration
|
||||
{
|
||||
public Uri BaseURI { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
}
|
||||
}
|
43
Program.cs
Normal file
43
Program.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ttrss_co_client
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static async Task Main(string[] args)
|
||||
{
|
||||
var conf = Configure();
|
||||
var ttrssClient = new ttrss.ApiClient(conf.BaseURI);
|
||||
await ttrssClient.Login(conf.Username, conf.Password);
|
||||
Console.WriteLine("Hello, World!");
|
||||
}
|
||||
static Configuration Configure(string configurationPath = "appsettings.json")
|
||||
{
|
||||
if (!File.Exists(configurationPath))
|
||||
{
|
||||
Console.Error.WriteLine($"could not find configuration at {configurationPath}! copying sample to that spot.");
|
||||
File.Copy("sample-appsettings.json", configurationPath); //and you know what, if that explodes at the OS level, the OS should give you an error
|
||||
return null;
|
||||
}
|
||||
var fileContents = File.ReadAllText(configurationPath);
|
||||
if (string.IsNullOrWhiteSpace(fileContents))
|
||||
{
|
||||
Console.Error.WriteLine($"configuration file at {configurationPath} was empty! overwriting with sample settings.");
|
||||
File.Copy("sample-appsettings.json", configurationPath, true);
|
||||
return null;
|
||||
}
|
||||
|
||||
var conf = JsonConvert.DeserializeObject<Configuration>(fileContents);
|
||||
|
||||
if (conf == null)
|
||||
{
|
||||
Console.Error.WriteLine($"configuration file at {configurationPath} was empty! overwriting with sample settings.");
|
||||
File.Copy("sample-appsettings.json", configurationPath, true);
|
||||
return null;
|
||||
}
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
5
sample-appsettings.json
Normal file
5
sample-appsettings.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"BaseUri": "https://ttrss.example.com/api/",
|
||||
"username": "guy who didn't configure",
|
||||
"password": "sordph1sh"
|
||||
}
|
15
ttrss-co-client.csproj
Normal file
15
ttrss-co-client.csproj
Normal file
@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<RootNamespace>ttrss_co_client</RootNamespace>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
209
ttrss/ApiClient.cs
Normal file
209
ttrss/ApiClient.cs
Normal file
@ -0,0 +1,209 @@
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using System.Net.Http.Json;
|
||||
|
||||
// https://tt-rss.org/wiki/ApiReference
|
||||
|
||||
namespace ttrss_co_client.ttrss
|
||||
{
|
||||
public class ApiClient
|
||||
{
|
||||
public Uri BaseURI { get; private set; }
|
||||
private HttpClient httpClient { get; set; }
|
||||
private string SessionId { get; set; } = null;
|
||||
private int api_level{get;set;}
|
||||
|
||||
public ApiClient(Uri baseUri)
|
||||
{
|
||||
BaseURI = baseUri;
|
||||
httpClient = new HttpClient() { BaseAddress = baseUri };
|
||||
}
|
||||
|
||||
public async Task Login(string username, string password)
|
||||
{
|
||||
var json = new
|
||||
{
|
||||
op = "login",
|
||||
user = username,
|
||||
password = password
|
||||
};
|
||||
var content = JsonContent.Create(json);
|
||||
var response = await (await httpClient.PostAsync(BaseURI, content)).Content.ReadAsStringAsync();
|
||||
var loginResult = JsonConvert.DeserializeObject<ttrss.messages.LoginResponse>(response);
|
||||
if (loginResult.status == 0)
|
||||
{
|
||||
SessionId = loginResult.content.session_id;
|
||||
api_level = loginResult.content.api_level ?? 1;
|
||||
Console.WriteLine(SessionId);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<int> GetApiLevel()
|
||||
{
|
||||
assertInitialized();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<string> GetVersion()
|
||||
{
|
||||
assertInitialized();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<bool> Logout()
|
||||
{
|
||||
assertInitialized();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<bool> IsLoggedIn()
|
||||
{
|
||||
assertInitialized();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<int> GetUnread()
|
||||
{
|
||||
assertInitialized();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task GetFeeds(int cat_id, bool unread_only, int limit, int offset, bool include_nested)
|
||||
{
|
||||
assertInitialized();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task GetCategories(bool unread_only, bool enable_nested, bool include_empty)
|
||||
{
|
||||
assertInitialized();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public enum VIEWMODE { All, Unread, Adaptive, Marked, Updated }
|
||||
public enum SORTORDER { Default, OldestFirst, NewestFirst }
|
||||
public async Task GetHeadlines(int feed_id, int limit, int skip, /*string filter, */ bool is_cat, bool show_excerpt, bool show_content, VIEWMODE view_mode, bool include_attachments, int since_id, bool include_nested, SORTORDER order_by, bool sanitize, bool force_update = false, bool has_sandbox = false, bool include_header)
|
||||
{
|
||||
await getHeadlines(feed_id, null, limit, skip, /*filter, */ is_cat, show_excerpt, show_content, view_mode, include_attachments, since_id, include_nested, order_by, sanitize, force_update, has_sandbox, include_header);
|
||||
}
|
||||
public async Task GetHeadlines(string feed_id, int limit, int skip, /*string filter, */ bool is_cat, bool show_excerpt, bool show_content, VIEWMODE view_mode, bool include_attachments, int since_id, bool include_nested, SORTORDER order_by, bool sanitize, bool force_update = false, bool has_sandbox = false, bool include_header)
|
||||
{
|
||||
await getHeadlines(null, feed_id, limit, skip, /*filter, */ is_cat, show_excerpt, show_content, view_mode, include_attachments, since_id, include_nested, order_by, sanitize, force_update, has_sandbox, include_header);
|
||||
}
|
||||
private async Task getHeadlines(int? int_feed_id, string string_feed_id, int limit, int skip, /*string filter, */ bool is_cat, bool show_excerpt, bool show_content, VIEWMODE view_mode, bool include_attachments, int since_id, bool include_nested, SORTORDER order_by, bool sanitize, bool force_update, bool has_sandbox, bool include_header)
|
||||
{
|
||||
assertInitialized();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public enum UPDATEMODE { SetFalse, SetTrue, Toggle }
|
||||
public enum UPDATEFIELD { starred, published, unread }
|
||||
public async Task<int> UpdateArticleField(UPDATEMODE mode, UPDATEFIELD field, params int[] ids)
|
||||
{
|
||||
//documentation: UpdateArticle - for note, we have a separate method UpdateArticleNote
|
||||
assertInitialized();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<int> UpdateArticleNote(string data, params int[] ids)
|
||||
{
|
||||
//documentation: UpdateArticle - for fields other than note, we have a separate method UpdateArticleField
|
||||
assertInitialized();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<IEnumerable<object>> GetArticle(params int[] article_id)
|
||||
{
|
||||
if (!article_id.Any())
|
||||
{
|
||||
throw new ArgumentException("need at least one article_id");
|
||||
}
|
||||
assertInitialized();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<Configuration> GetConfig()
|
||||
{
|
||||
assertInitialized();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
///<summary>
|
||||
///tell the feed to update. As opposed to updating our configuration of the feed.
|
||||
///</summary>
|
||||
public async Task UpdateFeed(int feed_id)
|
||||
{
|
||||
assertInitialized();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task<string> GetPref(string key)
|
||||
{
|
||||
assertInitialized();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public enum CATCHUPMODE { All, OneDay, OneWeek, TwoWeeks }
|
||||
public async Task CatchupFeed(int feed_id, bool is_cat, CATCHUPMODE mode = CATCHUPMODE.All)
|
||||
{
|
||||
assertInitialized();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task GetCounters(bool actual_feeds = true, bool labels = true, bool categories = true, bool tags = false)
|
||||
{
|
||||
assertInitialized();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task GetLabels(int? article_id)
|
||||
{
|
||||
assertInitialized();
|
||||
if(article_id != null)
|
||||
{
|
||||
assertApiLevel(5);
|
||||
}
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task SetArticleLabel(int label_id, bool assign, params int[] article_ids)
|
||||
{
|
||||
//there's a label "cache", i guess?
|
||||
assertInitialized();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task ShareToPublished(string title, Uri url, string content, bool sanitize = true)
|
||||
{
|
||||
assertInitialized();
|
||||
assertApiLevel(4);
|
||||
if(!sanitize)
|
||||
assertApiLevel(20);
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
///<summary>
|
||||
///<param name="login"/>if the feed requires basic HTTP auth; the login. (decidedly not self-explanatory, gdi)</param>
|
||||
///<param name="password"/>if the feed requires basic HTTP auth; the password. (decidedly not self-explanatory, gdi)</param>
|
||||
///</summary>
|
||||
public async Task SubscribeToFeed(Uri feed_url, int category_id, string login, string password)
|
||||
{
|
||||
assertInitialized();
|
||||
assertApiLevel(5);
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task UnsubscribeFeed()
|
||||
{
|
||||
assertInitialized();
|
||||
assertApiLevel(5);
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public async Task GetFeedTree()
|
||||
{
|
||||
assertInitialized();
|
||||
assertApiLevel(5);
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
private void assertInitialized()
|
||||
{
|
||||
if (SessionId == null)
|
||||
{
|
||||
throw new InvalidOperationException("no session ID - call Login first!");
|
||||
}
|
||||
}
|
||||
private void assertApiLevel(int ApiLevel)
|
||||
{
|
||||
if(ApiLevel > this.api_level)
|
||||
{
|
||||
throw new NotSupportedException($"method requires api level {ApiLevel}, have {this.api_level}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
13
ttrss/Configuration.cs
Normal file
13
ttrss/Configuration.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http.Json;
|
||||
|
||||
namespace ttrss_co_client.ttrss
|
||||
{
|
||||
public class Configuration
|
||||
{
|
||||
public string icons_dir { get; set; }
|
||||
public string icons_url { get; set; }
|
||||
public bool daemon_is_running { get; set; }
|
||||
public int num_feeds { get; set; }
|
||||
}
|
||||
}
|
17
ttrss/messages/LoginResponse.cs
Normal file
17
ttrss/messages/LoginResponse.cs
Normal file
@ -0,0 +1,17 @@
|
||||
namespace ttrss_co_client.ttrss.messages
|
||||
{
|
||||
public class LoginResponse
|
||||
{
|
||||
public int seq { get; set; }
|
||||
public int status { get; set; }
|
||||
public Content content { get; set; }
|
||||
|
||||
public class Content
|
||||
{
|
||||
public string session_id { get; set; }
|
||||
public Configuration config { get; set; }
|
||||
public int? api_level { get; set; }
|
||||
public string error { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user