diff --git a/BitSearch/BitSearch.API/BitSearch.API.csproj b/BitSearch/BitSearch.API/BitSearch.API.csproj new file mode 100644 index 0000000..00a14a9 --- /dev/null +++ b/BitSearch/BitSearch.API/BitSearch.API.csproj @@ -0,0 +1,12 @@ + + + + net5.0 + + + + + + + + diff --git a/BitSearch/BitSearch.API/Controllers/SearchController.cs b/BitSearch/BitSearch.API/Controllers/SearchController.cs new file mode 100644 index 0000000..96b84ba --- /dev/null +++ b/BitSearch/BitSearch.API/Controllers/SearchController.cs @@ -0,0 +1,104 @@ +using BitSearch.API.Models; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.WebUtilities; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Microsoft.Net.Http.Headers; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Net.Http.Json; +using System.Threading.Tasks; + +namespace BitSearch.API.Controllers +{ + [ApiController] + [Route("[controller]")] + public class SearchController : ControllerBase + { + + private readonly ILogger _logger; + private readonly IConfiguration Configuration; + private readonly IHttpClientFactory _httpClientFactory; + + public SearchController(ILogger logger, IConfiguration configuration, IHttpClientFactory httpClientFactory) + { + _logger = logger; + _httpClientFactory = httpClientFactory; + Configuration = configuration; + } + + [HttpGet("ranking")] + public async Task GetRanking() + { + var cryptoHash = new Dictionary() + { + {"Bitcoin", "#btc"}, + {"Etherum", "#eth"}, + {"Ripple", "xrp"}, + {"Litecoin", "#ltc"}, + {"Binance Coin", "#binance"} + }; + + var token = Configuration["Token"]; + var twitterClient = _httpClientFactory.CreateClient(); + twitterClient.BaseAddress = new Uri("https://api.twitter.com/2/tweets/counts/"); + twitterClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); + twitterClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + var ranking = new List(); + + foreach (KeyValuePair crypto in cryptoHash) + { + var requestUri = QueryHelpers.AddQueryString("recent", "query", crypto.Value); + var request = new HttpRequestMessage(HttpMethod.Get, requestUri); + var response = await twitterClient.SendAsync(request); + if (response.IsSuccessStatusCode) + { + var tweetsDto = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + ranking.Add(new CryptoRanking() { Name = crypto.Key, TweetAmount = tweetsDto.meta.total_tweet_count }); + } + } + + return Ok(ranking.OrderByDescending(r => r.TweetAmount)); + } + + [HttpGet("analise/{hash}")] + public async Task GetAnalysis(string hash) + { + var queryString = new Dictionary() + { + {"query", $"#{hash}"}, + {"max_results", "100"}, + {"tweet.fields", "lang,referenced_tweets"}, + }; + + var token = Configuration["Token"]; + var twitterClient = _httpClientFactory.CreateClient(); + twitterClient.BaseAddress = new Uri("https://api.twitter.com/2/tweets/search/"); + var requestUri = QueryHelpers.AddQueryString("recent", queryString); + var twiiterRequest = new HttpRequestMessage(HttpMethod.Get, requestUri); + twitterClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); + twitterClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + var response = await twitterClient.SendAsync(twiiterRequest); + + if (response.IsSuccessStatusCode) + { + var tweetsDto = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + tweetsDto.data = tweetsDto.data.Where(d => d.lang == "en"); + var microServiceClient = _httpClientFactory.CreateClient(); + var microServiceRequest = new HttpRequestMessage(HttpMethod.Get, "http://127.0.0.1:5000/analysis"); + microServiceRequest.Content = JsonContent.Create(tweetsDto); + var microServiceResponse = await microServiceClient.SendAsync(microServiceRequest); + + return Ok(await microServiceResponse.Content.ReadAsStringAsync()); + //return Ok(tweetsDto); + } + + return Ok(response); + } + } +} diff --git a/BitSearch/BitSearch.API/Models/BaseTweetsDto.cs b/BitSearch/BitSearch.API/Models/BaseTweetsDto.cs new file mode 100644 index 0000000..6179417 --- /dev/null +++ b/BitSearch/BitSearch.API/Models/BaseTweetsDto.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BitSearch.API.Models +{ + public class BaseTweetsDto + { + public IEnumerable data { get; set; } + } +} diff --git a/BitSearch/BitSearch.API/Models/CryptoRanking.cs b/BitSearch/BitSearch.API/Models/CryptoRanking.cs new file mode 100644 index 0000000..97d1af5 --- /dev/null +++ b/BitSearch/BitSearch.API/Models/CryptoRanking.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BitSearch.API.Models +{ + public class CryptoRanking + { + public string Name { get; set; } + public int TweetAmount { get; set; } + } +} diff --git a/BitSearch/BitSearch.API/Models/MetaData.cs b/BitSearch/BitSearch.API/Models/MetaData.cs new file mode 100644 index 0000000..e28a37e --- /dev/null +++ b/BitSearch/BitSearch.API/Models/MetaData.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BitSearch.API.Models +{ + public class MetaData + { + public int total_tweet_count { get; set; } + } +} diff --git a/BitSearch/BitSearch.API/Models/ReferencedTweets.cs b/BitSearch/BitSearch.API/Models/ReferencedTweets.cs new file mode 100644 index 0000000..27947ec --- /dev/null +++ b/BitSearch/BitSearch.API/Models/ReferencedTweets.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BitSearch.API.Models +{ + public class ReferencedTweets + { + public string type { get; set; } + public string id { get; set; } + } +} diff --git a/BitSearch/BitSearch.API/Models/TweetCount.cs b/BitSearch/BitSearch.API/Models/TweetCount.cs new file mode 100644 index 0000000..a3d3862 --- /dev/null +++ b/BitSearch/BitSearch.API/Models/TweetCount.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BitSearch.API.Models +{ + public class TweetCount + { + public MetaData meta { get; set; } + } +} diff --git a/BitSearch/BitSearch.API/Models/TweeterResponse.cs b/BitSearch/BitSearch.API/Models/TweeterResponse.cs new file mode 100644 index 0000000..8d7b0c8 --- /dev/null +++ b/BitSearch/BitSearch.API/Models/TweeterResponse.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BitSearch.API.Models +{ + public class TweeterResponse : BaseTweetsDto + { + } +} diff --git a/BitSearch/BitSearch.API/Models/TweetsDto.cs b/BitSearch/BitSearch.API/Models/TweetsDto.cs new file mode 100644 index 0000000..a3cd3f5 --- /dev/null +++ b/BitSearch/BitSearch.API/Models/TweetsDto.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BitSearch.API.Models +{ + public class TweetsDto + { + public string id { get; set; } + public string text { get; set; } + public string lang { get; set; } + public IEnumerable referenced_tweets { get; set; } + } +} diff --git a/BitSearch/BitSearch.API/Program.cs b/BitSearch/BitSearch.API/Program.cs new file mode 100644 index 0000000..a3e31fa --- /dev/null +++ b/BitSearch/BitSearch.API/Program.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BitSearch.API +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } +} diff --git a/BitSearch/BitSearch.API/Properties/launchSettings.json b/BitSearch/BitSearch.API/Properties/launchSettings.json new file mode 100644 index 0000000..d459ee6 --- /dev/null +++ b/BitSearch/BitSearch.API/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:62241", + "sslPort": 0 + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "BitSearch.API": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": "true", + "applicationUrl": "https://localhost:5001;http://localhost:5000" + } + } +} \ No newline at end of file diff --git a/BitSearch/BitSearch.API/Startup.cs b/BitSearch/BitSearch.API/Startup.cs new file mode 100644 index 0000000..dce4a80 --- /dev/null +++ b/BitSearch/BitSearch.API/Startup.cs @@ -0,0 +1,60 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.HttpsPolicy; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.OpenApi.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BitSearch.API +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + + services.AddControllers(); + services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo { Title = "BitSearch.API", Version = "v1" }); + }); + services.AddHttpClient(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + app.UseSwagger(); + app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "BitSearch.API v1")); + } + + app.UseHttpsRedirection(); + + app.UseRouting(); + + app.UseAuthorization(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } + } +} diff --git a/BitSearch/BitSearch.API/appsettings.Development.json b/BitSearch/BitSearch.API/appsettings.Development.json new file mode 100644 index 0000000..8983e0f --- /dev/null +++ b/BitSearch/BitSearch.API/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/BitSearch/BitSearch.API/appsettings.json b/BitSearch/BitSearch.API/appsettings.json new file mode 100644 index 0000000..051265a --- /dev/null +++ b/BitSearch/BitSearch.API/appsettings.json @@ -0,0 +1,12 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*", + "Token": "AAAAAAAAAAAAAAAAAAAAAJm8XwEAAAAAWyiq2ESxmQgVp5gCbvccbnLzfrE%3D1g4gSrKfNveU4E382aWh6JYkESNw09tsraYMFcdv6Wk87kQixh" + +} diff --git a/BitSearch/BitSearch.Tests/BitSearch.Tests.csproj b/BitSearch/BitSearch.Tests/BitSearch.Tests.csproj new file mode 100644 index 0000000..cc3d8ba --- /dev/null +++ b/BitSearch/BitSearch.Tests/BitSearch.Tests.csproj @@ -0,0 +1,16 @@ + + + + net5.0 + + false + + + + + + + + + + diff --git a/BitSearch/BitSearch.Tests/LoginTests.cs b/BitSearch/BitSearch.Tests/LoginTests.cs new file mode 100644 index 0000000..d7fe2ed --- /dev/null +++ b/BitSearch/BitSearch.Tests/LoginTests.cs @@ -0,0 +1,70 @@ +using NUnit.Framework; +using OpenQA.Selenium; +using OpenQA.Selenium.Chrome; + +namespace BitSearch.Tests +{ + public class Browser_ops + { + IWebDriver webDriver; + public void Init_Browser() + { + var options = new ChromeOptions(); + options.AcceptInsecureCertificates = true; + webDriver = new ChromeDriver("C:\\Program Files (x86)\\Google\\Chrome\\Application", options); + webDriver.Manage().Window.Maximize(); + } + public string Title + { + get { return webDriver.Title; } + } + public void Goto(string url) + { + webDriver.Url = url; + } + public void Close() + { + webDriver.Quit(); + } + public IWebDriver getDriver + { + get { return webDriver; } + } + } + + public class LoginTests + { + Browser_ops brow = new Browser_ops(); + string test_url = "https://localhost:44371/Identity/Account/Login"; + IWebDriver driver; + + [SetUp] + public void Setup() + { + brow.Init_Browser(); + driver = brow.getDriver; + } + + [Test] + public void VerifyValidLogin() + { + brow.Goto(test_url); + System.Threading.Thread.Sleep(2000); + driver.FindElement(By.XPath("//*[@id='Input_Email']")).SendKeys("testowy@mail.com"); + driver.FindElement(By.XPath("//*[@id='Input_Password']")).SendKeys("12#qwE"); + driver.FindElement(By.XPath("//*[@id='login-submit']")).Click(); + Assert.AreEqual(driver.Url, "https://localhost:44371/"); + } + + [Test] + public void VerifyInvalidLogin() + { + brow.Goto(test_url); + System.Threading.Thread.Sleep(2000); + driver.FindElement(By.XPath("//*[@id=\"Input_Email\"]")).SendKeys("wrong@mail.com"); + driver.FindElement(By.XPath("//*[@id='Input_Password']")).SendKeys("invalid"); + driver.FindElement(By.XPath("//*[@id='login-submit']")).Click(); + Assert.AreEqual(driver.FindElement(By.XPath("//*[@id='account']/div[1]/ul/li")).Text, "Invalid login attempt."); + } + } +} \ No newline at end of file diff --git a/BitSearch/BitSearch.sln b/BitSearch/BitSearch.sln index b0a04f5..080ce29 100644 --- a/BitSearch/BitSearch.sln +++ b/BitSearch/BitSearch.sln @@ -3,7 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31112.23 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitSearch", "BitSearch\BitSearch.csproj", "{F5F997CE-0BBE-478A-B7A3-828B0EAB8B99}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BitSearch", "BitSearch\BitSearch.csproj", "{F5F997CE-0BBE-478A-B7A3-828B0EAB8B99}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BitSearch.Tests", "BitSearch.Tests\BitSearch.Tests.csproj", "{8B871554-1F3D-4828-9642-B191B499A80C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitSearch.API", "BitSearch.API\BitSearch.API.csproj", "{08FC64E2-3128-4517-ADCA-D1BF8AF126F0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,6 +19,14 @@ Global {F5F997CE-0BBE-478A-B7A3-828B0EAB8B99}.Debug|Any CPU.Build.0 = Debug|Any CPU {F5F997CE-0BBE-478A-B7A3-828B0EAB8B99}.Release|Any CPU.ActiveCfg = Release|Any CPU {F5F997CE-0BBE-478A-B7A3-828B0EAB8B99}.Release|Any CPU.Build.0 = Release|Any CPU + {8B871554-1F3D-4828-9642-B191B499A80C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8B871554-1F3D-4828-9642-B191B499A80C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8B871554-1F3D-4828-9642-B191B499A80C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8B871554-1F3D-4828-9642-B191B499A80C}.Release|Any CPU.Build.0 = Release|Any CPU + {08FC64E2-3128-4517-ADCA-D1BF8AF126F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {08FC64E2-3128-4517-ADCA-D1BF8AF126F0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {08FC64E2-3128-4517-ADCA-D1BF8AF126F0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {08FC64E2-3128-4517-ADCA-D1BF8AF126F0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE