Skip to content

Commit 0a1636d

Browse files
authored
Merge pull request #221 from umbraco/v14/feature/43247-V14-Integrations-(Semrush)
V14/feature/43247 v14 integrations (semrush)
2 parents 4229bf7 + 7b70066 commit 0a1636d

File tree

90 files changed

+11199
-1336
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+11199
-1336
lines changed

.gitignore

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@ src/Umbraco.Cms.Integrations.Crm.Dynamics/wwwroot/*
1515
src/Umbraco.Cms.Integrations.Crm.ActiveCampaign/wwwroot/*
1616
!src/Umbraco.Cms.Integrations.Crm.ActiveCampaign/wwwroot/umbraco-package.json
1717
src/Umbraco.Cms.Integrations.Automation.Zapier/wwwroot
18-
src/Umbraco.Cms.Integrations.Commerce.Shopify/wwwroot
19-
src/Umbraco.Cms.Integrations.Crm.Hubspot/wwwroot
20-
18+
src/Umbraco.Cms.Integrations.SEO.Semrush/wwwroot/*
19+
!src/Umbraco.Cms.Integrations.SEO.Semrush/wwwroot/umbraco-package.json
2120

2221
# User-specific files
2322
*.suo
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"id": "Umbraco.Cms.Integrations.Crm.ActiveCampaign",
3+
"name": "Umbraco CMS Integrations: CRM - ActiveCampaign",
4+
"version": "3.0.0",
5+
"extensions": [
6+
{
7+
"name": "Umbraco EntryPoint",
8+
"alias": "Umb.Hubspot.EntryPoint",
9+
"type": "entryPoint",
10+
"js": "/App_Plugins/ActiveCampaignForms/activecampaign.js"
11+
}
12+
]
13+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using Asp.Versioning;
2+
using Microsoft.AspNetCore.Hosting;
3+
using Microsoft.AspNetCore.Http;
4+
using Microsoft.AspNetCore.Mvc;
5+
using Microsoft.Extensions.Options;
6+
using Umbraco.Cms.Integrations.SEO.Semrush.Configuration;
7+
using Umbraco.Cms.Integrations.SEO.Semrush.Models;
8+
using Umbraco.Cms.Integrations.SEO.Semrush.Services;
9+
10+
namespace Umbraco.Cms.Integrations.SEO.Semrush.Api.Management.Controllers
11+
{
12+
[ApiVersion("1.0")]
13+
[ApiExplorerSettings(GroupName = Constants.ManagementApi.SemrushGroupName)]
14+
public class AuthorizationController : SemrushControllerBase
15+
{
16+
public AuthorizationController(
17+
IOptions<SemrushSettings> options,
18+
IWebHostEnvironment webHostEnvironment,
19+
ISemrushTokenService semrushTokenService,
20+
ICacheHelper cacheHelper,
21+
TokenBuilder tokenBuilder,
22+
SemrushComposer.AuthorizationImplementationFactory authorizationImplementationFactory,
23+
IHttpClientFactory httpClientFactory) : base(options, webHostEnvironment, semrushTokenService, cacheHelper, tokenBuilder, authorizationImplementationFactory, httpClientFactory)
24+
{
25+
}
26+
27+
[HttpGet("auth")]
28+
[ProducesResponseType(typeof(ContentResult), StatusCodes.Status200OK)]
29+
public IActionResult OAuth(string code)
30+
{
31+
return Ok(new ContentResult
32+
{
33+
Content = string.IsNullOrEmpty(code)
34+
? JavascriptResponse.Fail("Authorization process failed.")
35+
: JavascriptResponse.Ok(code),
36+
ContentType = "text/html"
37+
});
38+
}
39+
}
40+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using Asp.Versioning;
2+
using Microsoft.AspNetCore.Hosting;
3+
using Microsoft.AspNetCore.Http;
4+
using Microsoft.AspNetCore.Mvc;
5+
using Microsoft.Extensions.Options;
6+
using Umbraco.Cms.Integrations.SEO.Semrush.Configuration;
7+
using Umbraco.Cms.Integrations.SEO.Semrush.Services;
8+
9+
namespace Umbraco.Cms.Integrations.SEO.Semrush.Api.Management.Controllers
10+
{
11+
[ApiVersion("1.0")]
12+
[ApiExplorerSettings(GroupName = Constants.ManagementApi.SemrushGroupName)]
13+
public class GetAuthorizationUrlController : SemrushControllerBase
14+
{
15+
public GetAuthorizationUrlController(
16+
IOptions<SemrushSettings> options,
17+
IWebHostEnvironment webHostEnvironment,
18+
ISemrushTokenService semrushTokenService,
19+
ICacheHelper cacheHelper,
20+
TokenBuilder tokenBuilder,
21+
SemrushComposer.AuthorizationImplementationFactory authorizationImplementationFactory,
22+
IHttpClientFactory httpClientFactory) : base(options, webHostEnvironment, semrushTokenService, cacheHelper, tokenBuilder, authorizationImplementationFactory, httpClientFactory)
23+
{
24+
}
25+
26+
[HttpGet("auth/url")]
27+
[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
28+
public IActionResult GetAuthorizationUrl() => Ok(_authorizationService.GetAuthorizationUrl());
29+
}
30+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using Asp.Versioning;
2+
using Microsoft.AspNetCore.Hosting;
3+
using Microsoft.AspNetCore.Http;
4+
using Microsoft.AspNetCore.Mvc;
5+
using Microsoft.Extensions.Options;
6+
using System.Reflection;
7+
using System.Text.Json;
8+
using Umbraco.Cms.Integrations.SEO.Semrush.Configuration;
9+
using Umbraco.Cms.Integrations.SEO.Semrush.Models.Dtos;
10+
using Umbraco.Cms.Integrations.SEO.Semrush.Services;
11+
12+
namespace Umbraco.Cms.Integrations.SEO.Semrush.Api.Management.Controllers
13+
{
14+
[ApiVersion("1.0")]
15+
[ApiExplorerSettings(GroupName = Constants.ManagementApi.SemrushGroupName)]
16+
public class GetColumnsController : SemrushControllerBase
17+
{
18+
public GetColumnsController(
19+
IOptions<SemrushSettings> options,
20+
IWebHostEnvironment webHostEnvironment,
21+
ISemrushTokenService semrushTokenService,
22+
ICacheHelper cacheHelper,
23+
TokenBuilder tokenBuilder,
24+
SemrushComposer.AuthorizationImplementationFactory authorizationImplementationFactory,
25+
IHttpClientFactory httpClientFactory) : base(options, webHostEnvironment, semrushTokenService, cacheHelper, tokenBuilder, authorizationImplementationFactory, httpClientFactory)
26+
{
27+
}
28+
29+
[HttpGet("columns")]
30+
[ProducesResponseType(typeof(IEnumerable<ColumnDto>), StatusCodes.Status200OK)]
31+
public IActionResult GetColumns()
32+
{
33+
string semrushColumnsPath = $"{Constants.EmbeddedResourceNamespace}.semrushColumns.json";
34+
var assembly = Assembly.GetExecutingAssembly();
35+
36+
_lock.EnterReadLock();
37+
38+
try
39+
{
40+
using (Stream stream = assembly.GetManifestResourceStream(semrushColumnsPath))
41+
{
42+
if (stream != null)
43+
{
44+
using (StreamReader reader = new StreamReader(stream))
45+
{
46+
string result = reader.ReadToEnd();
47+
var deserializeContent = JsonSerializer.Deserialize<IEnumerable<ColumnDto>>(result).Select(p =>
48+
new ColumnDto
49+
{
50+
Name = p.Name,
51+
Value = p.Value,
52+
Description = p.Description
53+
});
54+
55+
return Ok(deserializeContent);
56+
}
57+
}
58+
else
59+
{
60+
return Ok(Enumerable.Empty<ColumnDto>());
61+
}
62+
}
63+
64+
}
65+
catch (FileNotFoundException ex)
66+
{
67+
return Ok(Enumerable.Empty<ColumnDto>());
68+
}
69+
finally
70+
{
71+
_lock.ExitReadLock();
72+
}
73+
}
74+
}
75+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using Asp.Versioning;
2+
using Microsoft.AspNetCore.Hosting;
3+
using Microsoft.AspNetCore.Http;
4+
using Microsoft.AspNetCore.Mvc;
5+
using Microsoft.Extensions.Options;
6+
using Umbraco.Cms.Core.Services;
7+
using Umbraco.Cms.Integrations.SEO.Semrush.Configuration;
8+
using Umbraco.Cms.Integrations.SEO.Semrush.Models.Dtos;
9+
using Umbraco.Cms.Integrations.SEO.Semrush.Services;
10+
11+
namespace Umbraco.Cms.Integrations.SEO.Semrush.Api.Management.Controllers
12+
{
13+
[ApiVersion("1.0")]
14+
[ApiExplorerSettings(GroupName = Constants.ManagementApi.SemrushGroupName)]
15+
public class GetCurrentContentPropertiesController : SemrushControllerBase
16+
{
17+
private readonly IContentService _contentService;
18+
private readonly IContentTypeService _contentTypeService;
19+
public GetCurrentContentPropertiesController(IOptions<SemrushSettings> options,
20+
IWebHostEnvironment webHostEnvironment,
21+
ISemrushTokenService semrushTokenService,
22+
ICacheHelper cacheHelper,
23+
TokenBuilder tokenBuilder,
24+
SemrushComposer.AuthorizationImplementationFactory authorizationImplementationFactory,
25+
IContentService contentService,
26+
IContentTypeService contentTypeService,
27+
IHttpClientFactory httpClientFactory) : base(options, webHostEnvironment, semrushTokenService, cacheHelper, tokenBuilder, authorizationImplementationFactory, httpClientFactory)
28+
{
29+
_contentService = contentService;
30+
_contentTypeService = contentTypeService;
31+
}
32+
33+
[HttpGet("content-properties")]
34+
[ProducesResponseType(typeof(List<ContentPropertyDto>), StatusCodes.Status200OK)]
35+
public async Task<IActionResult> GetCurrentContentProperties(string contentId)
36+
{
37+
var propertyList = new List<ContentPropertyDto>();
38+
var currentContent = _contentService.GetById(Guid.Parse(contentId));
39+
var propertiesInCurrentContent = currentContent.Properties.ToList();
40+
var contentTypeOfCurrentContent = _contentTypeService.Get(currentContent.ContentType.Id);
41+
var contentGroupsOfCurrentContentType = contentTypeOfCurrentContent.PropertyGroups.ToList();
42+
43+
for(int i = 0; i < contentGroupsOfCurrentContentType.Count; i++)
44+
{
45+
var properties = contentGroupsOfCurrentContentType[i].PropertyTypes.ToList();
46+
47+
for(int j = 0; j < properties.Count; j++)
48+
{
49+
var property = properties[j];
50+
var value = propertiesInCurrentContent.Where(p => p.PropertyTypeId == property.Id).FirstOrDefault().Values;
51+
if(value != null && value.Count > 0)
52+
{
53+
propertyList.Add(new ContentPropertyDto
54+
{
55+
PropertyName = property.Name,
56+
PropertyGroup = contentGroupsOfCurrentContentType[i].Name,
57+
PropertyValue = value.FirstOrDefault().PublishedValue.ToString()
58+
});
59+
}
60+
}
61+
}
62+
63+
return Ok(propertyList);
64+
}
65+
}
66+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
using Asp.Versioning;
2+
using Microsoft.AspNetCore.Hosting;
3+
using Microsoft.AspNetCore.Http;
4+
using Microsoft.AspNetCore.Mvc;
5+
using Microsoft.Extensions.Options;
6+
using System.Reflection;
7+
using System.Text.Json;
8+
using Umbraco.Cms.Integrations.SEO.Semrush.Configuration;
9+
using Umbraco.Cms.Integrations.SEO.Semrush.Models.Dtos;
10+
using Umbraco.Cms.Integrations.SEO.Semrush.Services;
11+
12+
namespace Umbraco.Cms.Integrations.SEO.Semrush.Api.Management.Controllers
13+
{
14+
[ApiVersion("1.0")]
15+
[ApiExplorerSettings(GroupName = Constants.ManagementApi.SemrushGroupName)]
16+
public class GetDataSourcesController : SemrushControllerBase
17+
{
18+
public GetDataSourcesController(IOptions<SemrushSettings> options,
19+
IWebHostEnvironment webHostEnvironment,
20+
ISemrushTokenService semrushTokenService,
21+
ICacheHelper cacheHelper,
22+
TokenBuilder tokenBuilder,
23+
SemrushComposer.AuthorizationImplementationFactory authorizationImplementationFactory,
24+
IHttpClientFactory httpClientFactory) : base(options, webHostEnvironment, semrushTokenService, cacheHelper, tokenBuilder, authorizationImplementationFactory, httpClientFactory)
25+
{
26+
}
27+
28+
[HttpGet("data-sources")]
29+
[ProducesResponseType(typeof(DataSourceDto), StatusCodes.Status200OK)]
30+
public IActionResult GetDataSources()
31+
{
32+
string semrushDataSourcesPath = $"{Constants.EmbeddedResourceNamespace}.semrushDataSources.json";
33+
var assembly = Assembly.GetExecutingAssembly();
34+
35+
_lock.EnterReadLock();
36+
try
37+
{
38+
using (Stream stream = assembly.GetManifestResourceStream(semrushDataSourcesPath))
39+
{
40+
if (stream != null)
41+
{
42+
using (StreamReader reader = new StreamReader(stream))
43+
{
44+
string result = reader.ReadToEnd();
45+
var dataSourceDto = new DataSourceDto
46+
{
47+
Items = JsonSerializer.Deserialize<List<DataSourceItemDto>>(result).Select(p =>
48+
new DataSourceItemDto
49+
{
50+
Code = p.Code,
51+
Region = p.Region,
52+
ResearchTypes = p.ResearchTypes,
53+
GoogleSearchDomain = p.GoogleSearchDomain
54+
})
55+
};
56+
57+
return Ok(dataSourceDto);
58+
}
59+
}
60+
else
61+
{
62+
return Ok(new DataSourceDto());
63+
}
64+
}
65+
}
66+
catch (FileNotFoundException ex)
67+
{
68+
return Ok(new DataSourceDto());
69+
}
70+
finally
71+
{
72+
_lock.ExitReadLock();
73+
}
74+
}
75+
}
76+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using Asp.Versioning;
2+
using Microsoft.AspNetCore.Hosting;
3+
using Microsoft.AspNetCore.Http;
4+
using Microsoft.AspNetCore.Mvc;
5+
using Microsoft.Extensions.Options;
6+
using System.Text.Json;
7+
using Umbraco.Cms.Integrations.SEO.Semrush.Configuration;
8+
using Umbraco.Cms.Integrations.SEO.Semrush.Models.Dtos;
9+
using Umbraco.Cms.Integrations.SEO.Semrush.Services;
10+
11+
namespace Umbraco.Cms.Integrations.SEO.Semrush.Api.Management.Controllers
12+
{
13+
[ApiVersion("1.0")]
14+
[ApiExplorerSettings(GroupName = Constants.ManagementApi.SemrushGroupName)]
15+
public class GetRelatedPhrasesController : SemrushControllerBase
16+
{
17+
public GetRelatedPhrasesController(
18+
IOptions<SemrushSettings> options,
19+
IWebHostEnvironment webHostEnvironment,
20+
ISemrushTokenService semrushTokenService,
21+
ICacheHelper cacheHelper,
22+
TokenBuilder tokenBuilder,
23+
SemrushComposer.AuthorizationImplementationFactory authorizationImplementationFactory,
24+
IHttpClientFactory httpClientFactory) : base(options, webHostEnvironment, semrushTokenService, cacheHelper, tokenBuilder, authorizationImplementationFactory, httpClientFactory)
25+
{
26+
}
27+
28+
[HttpGet("related-phrases")]
29+
[ProducesResponseType(typeof(RelatedPhrasesDto), StatusCodes.Status200OK)]
30+
public async Task<IActionResult> GetRelatedPhrases(string phrase, int pageNumber, string dataSource, string method)
31+
{
32+
string cacheKey = $"{dataSource}-{method}-{phrase}";
33+
34+
if (_cacheHelper.TryGetCachedItem<RelatedPhrasesDto>(cacheKey, out var relatedPhrasesDto) && relatedPhrasesDto.Data != null)
35+
{
36+
relatedPhrasesDto.TotalPages = (int)Math.Ceiling((double)relatedPhrasesDto.Data.Rows.Count / Constants.DefaultPageSize);
37+
relatedPhrasesDto.Data.Rows = relatedPhrasesDto.Data.Rows
38+
.Skip((pageNumber - 1) * Constants.DefaultPageSize)
39+
.Take(Constants.DefaultPageSize)
40+
.ToList();
41+
42+
return Ok(relatedPhrasesDto);
43+
}
44+
45+
_semrushTokenService.TryGetParameters(Constants.TokenDbKey, out TokenDto token);
46+
47+
var httpClient = _clientFactory.CreateClient();
48+
var response = await httpClient
49+
.GetAsync(string.Format(Constants.SemrushKeywordsEndpoint, _settings.BaseUrl, method, token.AccessToken, phrase, dataSource));
50+
51+
if (response.IsSuccessStatusCode)
52+
{
53+
var responseContent = await response.Content.ReadAsStringAsync();
54+
55+
var relatedPhrasesDeserialized = JsonSerializer.Deserialize<RelatedPhrasesDto>(responseContent);
56+
57+
if (!relatedPhrasesDeserialized.IsSuccessful) return Ok(relatedPhrasesDeserialized);
58+
59+
_cacheHelper.AddCachedItem(cacheKey, responseContent);
60+
61+
relatedPhrasesDeserialized.TotalPages = (int)Math.Ceiling((double)relatedPhrasesDeserialized.Data.Rows.Count / Constants.DefaultPageSize);
62+
relatedPhrasesDeserialized.Data.Rows = relatedPhrasesDeserialized.Data.Rows
63+
.Skip((pageNumber - 1) * Constants.DefaultPageSize)
64+
.Take(Constants.DefaultPageSize)
65+
.ToList();
66+
67+
return Ok(relatedPhrasesDeserialized);
68+
}
69+
70+
return Ok(relatedPhrasesDto);
71+
}
72+
}
73+
}

0 commit comments

Comments
 (0)