38 Commits

Author SHA1 Message Date
Shannon d5b0abd1ae fixing search 2017-06-27 10:42:37 +10:00
Niels Hartvig 81ba5bd022 Merge pull request #118 from bjarnef/dev-OUR-451-update
Update Fancybox to latest v3
2017-06-26 14:57:38 +02:00
Bjarne Fyrstenborg 96a3ca71a7 Update Fancybox to latest v3 2017-06-23 17:30:45 +02:00
Niels Hartvig a8e253553a Removes people with 0 contributions from list 2017-06-23 13:16:59 +02:00
Niels Hartvig 91280b18f6 Fix from Pull Request #84 2017-06-23 12:59:02 +02:00
Niels Hartvig fbb8ef1ba0 Merge pull request #100 from stvnhrlnd/OUR-441
Our 441
2017-06-23 12:03:02 +02:00
Niels Hartvig 3f46d94a93 Merge branch 'naepalm-feature-icon-size-tweaks' 2017-06-23 11:50:56 +02:00
Niels Hartvig 161fcc7f01 Updates PR with bjarnef's review comments 2017-06-23 11:50:34 +02:00
Niels Hartvig 5e2cb68299 Merge branch 'feature-icon-size-tweaks' of https://github.com/naepalm/OurUmbraco into naepalm-feature-icon-size-tweaks 2017-06-23 11:28:29 +02:00
Niels Hartvig e6a5b59ac6 Merge pull request #117 from umbraco/temp-OUR-456
Removes RTs from twitter feed
2017-06-23 11:26:43 +02:00
Niels Hartvig 2ffa61564c Removes RTs from twitter feed 2017-06-23 11:03:06 +02:00
Niels Hartvig a1d48afeca Merge pull request #106 from bjarnef/dev-OUR-451
Update to FancyBox v3
2017-06-23 10:55:13 +02:00
Niels Hartvig a51e57737b Merge branch 'bjarnef-dev-githubfilecache' 2017-06-23 10:48:42 +02:00
Niels Hartvig 1c8fcef754 Removing throwing error upon github api not returning 200
(we already log it and the Accepted status with empty data set is
(hopefully) a throttle issue)
2017-06-23 10:47:50 +02:00
Niels Hartvig ab4ca0015e Merge with master 2017-06-23 10:38:52 +02:00
Niels Hartvig f9014d649b Fixes issue with contrib not counting commits but additions+deletions 2017-06-23 10:09:04 +02:00
hartvig adf67fd89f Merge pull request #116 from Weegy/GitGubContributors
Git gub contributors
2017-06-23 08:54:03 +02:00
Sebastiaan Janssen 805709a91b Set frontend auth cookie to be sent over secure channel only 2017-06-23 08:22:44 +02:00
Marcel Wege 40a6aaa1a8 foreach to Linq.SUM 2017-06-22 17:29:57 +02:00
Marcel Wege 5e51dad445 GitHubContributors 2017-06-22 16:56:35 +02:00
hartvig f2d9cc0c0b Merge pull request #110 from emmagarland/githubcontributors
Github contributors
2017-06-22 14:43:45 +02:00
Niels Hartvig a40f8f9a28 Fixes cache setting 2017-06-22 14:39:38 +02:00
Niels Hartvig 355c4184ef Update github list to only include people from the last 12 months 2017-06-22 14:37:32 +02:00
Sebastiaan Janssen 50bdd7647a Redirect docs for products to Add-on 2017-06-22 10:16:14 +02:00
hartvig 47c85e633b Adding umbLeeds to meetup list 2017-06-19 15:31:34 +02:00
Sebastiaan Janssen f82cda981c Whitelist branches to get the documentation from and make it a little bit safer (don't start with deleting everything until we're pretty sure it's going to be rebuilt correctly afterwards). 2017-06-13 13:35:55 +02:00
Sebastiaan Janssen aded9ec437 Fixing docs 2017-06-13 10:17:45 +02:00
Shannon bdcad7665f fixes string interpolation 2017-06-07 08:34:12 +02:00
Per Ploug 850b61fc4f Merge pull request #114 from umbraco/lesson-documentation-controller
remove dollars
2017-06-07 08:04:30 +02:00
Bjarne Fyrstenborg 1ea05d8107 Write contributors to json file and use file cached disk value 2017-06-06 16:27:21 +02:00
Emma Garland 60b7347586 Updated contributions to commits 2017-06-05 20:55:12 +01:00
Emma Garland b35d45bf31 Updated contribution link 2017-06-05 20:38:26 +01:00
Bjarne Fyrstenborg e3c52baf3a Update to FancyBox v3 2017-05-15 19:12:35 +02:00
Janae Cram 0cef4124db Fixes issue #OUR-449. 2017-05-05 13:13:43 -07:00
Steven 87847769ce Update forum partial
Show next page link when current page is less than the total number of pages. Keeps pagination consistent with projects list.
2017-03-04 15:43:46 +00:00
Steven 49c50046c9 Update search JavaScript
Reset page number to 1 when search filters are changed.
2017-03-04 15:11:22 +00:00
Steven c93e4d1e2d Update topic service and forum partial to fix pagination issue
Add new parameters to count method for unsolved and no reply filters. Update view to pass in these parameters.
2017-03-04 14:50:46 +00:00
Steven 686e3deb6c Update forum pagination links
Preserve query string parameters in pagination links so that topic filters do not get reset when switching between pages.
2017-03-04 14:23:19 +00:00
20 changed files with 456 additions and 257 deletions
+3 -2
View File
@@ -62,7 +62,7 @@ function GetSearchFilters(cssClass) {
} }
var forumId = $('#selectCategory').val(); var forumId = $('#selectCategory').val();
if(forumId !== undefined) { if(forumId) {
forumId = forumId.replace(/([A-Za-z])\w+/g, ""); forumId = forumId.replace(/([A-Za-z])\w+/g, "");
} }
@@ -365,7 +365,8 @@ $('#search-options input[type=checkbox]').click(function () {
newUri = updateQueryString("order", orderValue, window.location.href); newUri = updateQueryString("order", orderValue, window.location.href);
} }
} else { } else {
newUri = updateQueryString(this.name, this.checked, window.location.href); newUri = updateQueryString(this.name, this.checked, window.location.href);
newUri = updateQueryString("page", 1, newUri);
} }
console.log(newUri); console.log(newUri);
window.location = newUri; window.location = newUri;
+171 -171
View File
@@ -1,174 +1,174 @@
body.packages { body.packages {
nav { nav {
h3 { h3 {
&:hover { &:hover {
opacity: .8; opacity: .8;
} }
} }
h4 { h4 {
opacity: .7; opacity: .7;
margin: .5rem 0 .5rem; margin: .5rem 0 .5rem;
} }
} }
li { li {
h3 { h3 {
opacity: .5; opacity: .5;
} }
&.open, &.active { &.open, &.active {
h3, a { h3, a {
opacity: 1; opacity: 1;
color: #000 !important; color: #000 !important;
} }
} }
&.active > ul { &.active > ul {
max-height: 100%; max-height: 100%;
} }
} }
} }
.packages-content { .packages-content {
.search-big { .search-big {
margin-bottom: 0; margin-bottom: 0;
margin-top: 20px; margin-top: 20px;
} }
h1 { h1 {
margin: 1em 0 10px; margin: 1em 0 10px;
font-size: 2.1rem; font-size: 2.1rem;
} }
.package { .package {
margin-bottom: 15px; margin-bottom: 15px;
padding: 20px; padding: 20px;
transition: all .1s linear; transition: all .1s linear;
cursor: pointer; cursor: pointer;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
border-radius: 3px; border-radius: 3px;
border: 1px solid #e9e9e9; border: 1px solid #e9e9e9;
&:hover { &:hover {
@include box-shadow(2); @include box-shadow(2);
.icon { .icon {
transform: scale(1.1); transform: scale(1.1);
} }
} }
} }
.box { .box {
border: none; border: none;
border-bottom: 1px solid whitesmoke; border-bottom: 1px solid whitesmoke;
width: 100%; width: 100%;
.row{ .row{
width:100%; width:100%;
} }
h3 { h3 {
font-size: 1.1rem; font-size: 1.1rem;
margin-bottom: .5rem; margin-bottom: .5rem;
font-weight: 600; font-weight: 600;
a { a {
color: $color-headline; color: $color-headline;
&:hover { &:hover {
color: $color-our; color: $color-our;
} }
} }
} }
img { img {
max-width: 100%; max-width: 100%;
height: auto; height: auto;
display: block; display: block;
vertical-align: middle; vertical-align: middle;
@media (min-width: $md) { @media (min-width: $md) {
} }
} }
.col-xs-2 { .col-xs-2 {
vertical-align: middle !important; vertical-align: middle !important;
padding: 0 !important; padding: 0 !important;
} }
.other { .other {
margin-top: 30px; margin-top: 30px;
} }
.stats { .stats {
left: calc(16.666666666666664% + 15px); left: calc(16.666666666666664% + 15px);
font-family: Consolas, "Liberation Mono", Menlo, Monaco, Courier, monospace; font-family: Consolas, "Liberation Mono", Menlo, Monaco, Courier, monospace;
font-size: .75rem; font-size: .75rem;
i { i {
margin-left: 3px; margin-left: 3px;
font-size: .9rem; font-size: .9rem;
} }
span { span {
&:first-child { &:first-child {
margin-right: 0px; margin-right: 0px;
} }
} }
} }
p { p {
font-size: .9rem; font-size: .9rem;
color: $color-text; color: $color-text;
opacity: 1; opacity: 1;
} }
.package-badge { .package-badge {
position: absolute; position: absolute;
right: 15px; right: 15px;
bottom: -3px; bottom: -3px;
@media (min-width: $md) { @media (min-width: $md) {
position: absolute; position: absolute;
right: 0; right: 0;
bottom: 25px; bottom: 25px;
} }
} }
.karma , .downloads { .karma , .downloads {
color: #000; color: #000;
span { span {
transform: translate(0, 2px); transform: translate(0, 2px);
display: inline-block; display: inline-block;
} }
} }
&.liked { &.liked {
.karma { .karma {
i { i {
color: $color-red; color: $color-red;
} }
} }
} }
} }
.name { .name {
font-size: 1rem; font-size: 1rem;
line-height: 1.3; line-height: 1.3;
font-weight: bold; font-weight: bold;
} }
.description { .description {
font-size: .8rem; font-size: .8rem;
margin-top: 3px; margin-top: 3px;
max-height: 28px; max-height: 28px;
overflow: hidden; overflow: hidden;
} }
} }
@@ -157,6 +157,10 @@ section.forum {
max-width: 112px; max-width: 112px;
height: auto; height: auto;
.package-forum-activity & {
border-radius: 0;
}
@media (min-width: $md) { @media (min-width: $md) {
width: 58px; width: 58px;
} }
+3 -3
View File
@@ -14,7 +14,7 @@
Html.RequiresCss("~/assets/css/style.min.css", 0); Html.RequiresCss("~/assets/css/style.min.css", 0);
Html.RequiresCss("https://fonts.googleapis.com/css?family=Asap:400,700,400italic,700italic", 0); Html.RequiresCss("https://fonts.googleapis.com/css?family=Asap:400,700,400italic,700italic", 0);
Html.RequiresCss("https://cdnjs.cloudflare.com/ajax/libs/fancybox/2.1.5/jquery.fancybox.min.css", 0); Html.RequiresCss("https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.1.20/jquery.fancybox.min.css", 0);
Html.RequiresJs("https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.13.1/jquery.validate.min.js"); Html.RequiresJs("https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.13.1/jquery.validate.min.js");
@@ -23,7 +23,7 @@
Html.RequiresJs("https://cdnjs.cloudflare.com/ajax/libs/pagedown/1.0/Markdown.Editor.js"); Html.RequiresJs("https://cdnjs.cloudflare.com/ajax/libs/pagedown/1.0/Markdown.Editor.js");
Html.RequiresJs("https://cdnjs.cloudflare.com/ajax/libs/pagedown/1.0/Markdown.Sanitizer.js"); Html.RequiresJs("https://cdnjs.cloudflare.com/ajax/libs/pagedown/1.0/Markdown.Sanitizer.js");
Html.RequiresJs("https://cdnjs.cloudflare.com/ajax/libs/mustache.js/0.8.1/mustache.min.js"); Html.RequiresJs("https://cdnjs.cloudflare.com/ajax/libs/mustache.js/0.8.1/mustache.min.js");
Html.RequiresJs("https://cdnjs.cloudflare.com/ajax/libs/fancybox/2.1.5/jquery.fancybox.min.js"); Html.RequiresJs("https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.1.20/jquery.fancybox.min.js");
Html.RequiresJs("~/assets/js/jquery.ajaxfileupload.js"); Html.RequiresJs("~/assets/js/jquery.ajaxfileupload.js");
@@ -90,7 +90,7 @@
<!--[if lt IE 9]> <!--[if lt IE 9]>
<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.7.1/modernizr.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.7.1/modernizr.min.js"></script>
<![endif]--> <![endif]-->
<script type="text/javascript" src="https://code.jquery.com/jquery-1.7.2.min.js"></script> <script type="text/javascript" src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
@Html.Partial("~/Views/Partials/Community/JsValues.cshtml") @Html.Partial("~/Views/Partials/Community/JsValues.cshtml")
@@ -140,7 +140,6 @@ else
<div class="col-md-12"> <div class="col-md-12">
<h1 class="text-center">GitHub Contributions</h1> <h1 class="text-center">GitHub Contributions</h1>
<p> <p>
Contributions to Umbraco GitHub repositories
<small class="link-list"> <small class="link-list">
Contributions to default branches for Contributions to default branches for
<a href="https://github.com/umbraco/Umbraco-CMS" target="_blank" title="Umbraco-CMS">Umbraco-CMS</a>, <a href="https://github.com/umbraco/Umbraco-CMS" target="_blank" title="Umbraco-CMS">Umbraco-CMS</a>,
@@ -153,7 +152,7 @@ else
</p> </p>
</div> </div>
<div class="col-md-12"> <div class="col-md-12">
<small>GitHub contributors</small> <small>Contributions the last 12 months (number indicating accepted commits)</small>
</div> </div>
<div class="col-md-12 flex forum-thread" id="github-contributors"> <div class="col-md-12 flex forum-thread" id="github-contributors">
@@ -161,7 +160,7 @@ else
</div> </div>
<div class="col-md-12 goto-forum"> <div class="col-md-12 goto-forum">
<a class="button green" href="https://github.com/umbraco" target="_blank">Contribute to Umbraco on GitHub &rarr;</a> <a class="button green" href="https://our.umbraco.org/contribute">Contribute to Umbraco &rarr;</a>
</div> </div>
</div> </div>
@@ -5,6 +5,9 @@
@inherits OurUmbraco.Our.Models.OurUmbracoTemplatePage @inherits OurUmbraco.Our.Models.OurUmbracoTemplatePage
@{ @{
// Save query string for use in pagination links
var queryString = HttpUtility.ParseQueryString(Request.QueryString.ToString());
const int pagesToShowLeft = 4; const int pagesToShowLeft = 4;
int page; int page;
if (!int.TryParse(Request["page"], out page)) if (!int.TryParse(Request["page"], out page))
@@ -40,9 +43,9 @@
TimeSpan.FromSeconds(4)); TimeSpan.FromSeconds(4));
} }
var totalCountKey = "OurForumForumThreadCount[" + cat + "]"; var totalCountKey = "OurForumForumThreadCount[" + cat + unsolved + noreplies + "]";
var totalTopics = (int)cache.GetCacheItem(totalCountKey, var totalTopics = (int)cache.GetCacheItem(totalCountKey,
() => topicService.GetAllTopicsCount(cat), () => topicService.GetAllTopicsCount(cat, unsolved, noreplies),
TimeSpan.FromMinutes(1)); TimeSpan.FromMinutes(1));
var pages = (totalTopics / pageSize) + 1; var pages = (totalTopics / pageSize) + 1;
@@ -168,19 +171,22 @@
<nav class="pagination" role="navigation"> <nav class="pagination" role="navigation">
@if (page > 1) @if (page > 1)
{ {
<a class="prev" href="?page=@(page - 1)">Prev</a> queryString["page"] = (page - 1).ToString();
<a class="prev" href="?@queryString">Prev</a>
<span>&hellip;</span> <span>&hellip;</span>
} }
@for (var i = (page - 1 > 0 ? page - 1 : 1); i < (page + (pagesToShowLeft - (page - 1 > 0 ? 1 : 0))) && i <= pages; i++) @for (var i = (page - 1 > 0 ? page - 1 : 1); i < (page + (pagesToShowLeft - (page - 1 > 0 ? 1 : 0))) && i <= pages; i++)
{ {
<a class="@Umbraco.If(i == page, "active")" href="?page=@i">@i</a> queryString["page"] = i.ToString();
<a class="@Umbraco.If(i == page, "active")" href="?@queryString">@i</a>
} }
@if (page < (pages - 3)) @if (page < pages)
{ {
queryString["page"] = (page + 1).ToString();
<span>&hellip;</span> <span>&hellip;</span>
<a class="next" href="?page=@(page + 1)">Next</a> <a class="next" href="?@queryString">Next</a>
} }
</nav> </nav>
@@ -4,12 +4,10 @@
{ {
foreach (var contributor in Model.Contributors) foreach (var contributor in Model.Contributors)
{ {
var author = contributor.Author; <a href="@contributor.AuthorUrl" class="contributor" target="_blank" title="@contributor.AuthorLogin">
if (author != null)
{
<a href="@author.HtmlUrl" class="contributor" target="_blank" title="@author.Login">
<div class="avatar"> <div class="avatar">
<img alt="@author.Login" src="@author.AvatarUrl&s=112" /> <img alt="@contributor.AuthorLogin" src="@contributor.AuthorAvatarUrl&s=112"
srcset="@contributor.AuthorAvatarUrl&s=224 2x, @contributor.AuthorAvatarUrl&s=336 3x" />
<span class="contrib-count" title="@(contributor.TotalCommits + " " + (contributor.TotalCommits == 1 ? "contribution" : "contributions"))"> <span class="contrib-count" title="@(contributor.TotalCommits + " " + (contributor.TotalCommits == 1 ? "contribution" : "contributions"))">
@contributor.TotalCommits @contributor.TotalCommits
</span> </span>
@@ -22,7 +20,6 @@
</div> </div>
</div> </div>
</a> </a>
}
} }
<div class="loadmore"> <div class="loadmore">
<a class="button transparent" href="#" onclick="loadAllGitHubContributors(); return false;">Load more</a> <a class="button transparent" href="#" onclick="loadAllGitHubContributors(); return false;">Load more</a>
@@ -185,7 +185,9 @@
defaultScreenshot = childContent.GetPropertyValue("defaultScreenshotPath", false, "/css/img/package2.png"); defaultScreenshot = childContent.GetPropertyValue("defaultScreenshotPath", false, "/css/img/package2.png");
} }
} }
<img src="@Utils.GetScreenshotPath(defaultScreenshot)?bgcolor=fff&width=50&height=50&format=png" /> <img src="@Utils.GetScreenshotPath(defaultScreenshot)?bgcolor=fff&width=50&height=50&format=png"
srcset="@Utils.GetScreenshotPath(defaultScreenshot)?bgcolor=fff&width=100&height=100&format=png 2x,
@Utils.GetScreenshotPath(defaultScreenshot)?bgcolor=fff&width=150&height=150&format=png 3x" />
</div> </div>
<div class="col-xs-10 col-md-6"> <div class="col-xs-10 col-md-6">
<div class="forum-thread-text"> <div class="forum-thread-text">
@@ -81,7 +81,7 @@
@foreach (var image in screenshots) @foreach (var image in screenshots)
{ {
<a class="fancybox" rel="gallery1" href="@Utils.GetScreenshotPath(image.Path)" title=""> <a class="fancybox" data-fancybox="package-gallery" href="@Utils.GetScreenshotPath(image.Path)" title="">
<img src="@Utils.GetScreenshotPath(image.Path)?bgcolor=fff&height=154&width=281&format=png" alt=""/> <img src="@Utils.GetScreenshotPath(image.Path)?bgcolor=fff&height=154&width=281&format=png" alt=""/>
</a> </a>
} }
@@ -236,7 +236,7 @@
<a href="@forum.Url" class="forum-thread"> <a href="@forum.Url" class="forum-thread">
<div class="row"> <div class="row">
<div class="col-xs-10 col-md-0"> <div class="col-xs-12 col-md-12">
<div class="forum-thread-text"> <div class="forum-thread-text">
<h3>@forum.Name</h3> <h3>@forum.Name</h3>
<p>@forum.forumDescription</p> <p>@forum.forumDescription</p>
+4 -3
View File
@@ -18,9 +18,10 @@
(function () { (function () {
$(".fancybox") $(".fancybox")
.fancybox({ .fancybox({
openEffect: 'none', // options
closeEffect: 'none', loop: true,
padding: 0 arrows: true,
infobar: false
}); });
})(); })();
</script> </script>
@@ -32,4 +32,5 @@ UmbCardiff
meet-umbraco-the-umbraco-meetup meet-umbraco-the-umbraco-meetup
umBristol umBristol
Oslo-Umbraco-Meetup Oslo-Umbraco-Meetup
Orange-County-Umbraco-Web-Technologies Orange-County-Umbraco-Web-Technologies
umbLeeds
+2
View File
@@ -2,5 +2,7 @@
<configuration> <configuration>
<sources> <sources>
<add url="https://github.com/umbraco/UmbracoDocs/archive/master.zip" folder="" /> <add url="https://github.com/umbraco/UmbracoDocs/archive/master.zip" folder="" />
<!-- Comma separated list of branches we will pull documentation from -->
<allowedBranches>master</allowedBranches>
</sources> </sources>
</configuration> </configuration>
+6 -2
View File
@@ -308,7 +308,7 @@
</buildProviders> </buildProviders>
</compilation> </compilation>
<authentication mode="Forms"> <authentication mode="Forms">
<forms name="yourAuthCookie" loginUrl="login.aspx" protection="All" path="/" slidingExpiration="true" timeout="525600" /> <forms requireSSL="true" name="yourAuthCookie" loginUrl="login.aspx" protection="All" path="/" slidingExpiration="true" timeout="525600" />
</authentication> </authentication>
<authorization> <authorization>
<allow users="?" /> <allow users="?" />
@@ -506,6 +506,10 @@
</conditions> </conditions>
<action type="Redirect" url="{C:1}" redirectType="Permanent" appendQueryString="true" /> <action type="Redirect" url="{C:1}" redirectType="Permanent" appendQueryString="true" />
</rule> </rule>
<rule name="DocsProductsToAddons" patternSyntax="Wildcard" stopProcessing="true">
<match url="documentation/products/*" />
<action type="Redirect" url="/documentation/Add-ons/{R:1}" redirectType="Permanent" appendQueryString="true" />
</rule>
<!-- WIKI --> <!-- WIKI -->
<rule name="RedirectWikiEvents" patternSyntax="Wildcard"> <rule name="RedirectWikiEvents" patternSyntax="Wildcard">
<match url="wiki/reference/api-cheatsheet/using-applicationbase-to-register-events/*" /> <match url="wiki/reference/api-cheatsheet/using-applicationbase-to-register-events/*" />
@@ -691,4 +695,4 @@
</httpProtocol> </httpProtocol>
</system.webServer> </system.webServer>
</location> </location>
</configuration> </configuration>
@@ -9,6 +9,9 @@ using RestSharp;
using Umbraco.Core.Cache; using Umbraco.Core.Cache;
using Umbraco.Core.Logging; using Umbraco.Core.Logging;
using Umbraco.Web.Mvc; using Umbraco.Web.Mvc;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.Text;
namespace OurUmbraco.Community.Controllers namespace OurUmbraco.Community.Controllers
{ {
@@ -27,68 +30,144 @@ namespace OurUmbraco.Community.Controllers
"Umbraco.Deploy.ValueConnectors" "Umbraco.Deploy.ValueConnectors"
}; };
protected string JsonPath
{
get { return Server.MapPath("~/App_Data/TEMP/GithubContributors.json"); }
}
public List<GitHubCachedGlobalContributorModel> GetCachedContributors()
{
if (!System.IO.File.Exists(JsonPath)) throw new Exception("The JSON file doesn't exist on disk");
List<GitHubCachedGlobalContributorModel> temp = new List<GitHubCachedGlobalContributorModel>();
// Parse the JSON file from disk
foreach (JToken token in Skybrud.Essentials.Json.JsonUtils.LoadJsonArray(JsonPath))
{
temp.Add(token.ToObject<GitHubCachedGlobalContributorModel>());
}
return temp;
}
/// <summary> /// <summary>
/// Gets data for all GitHub contributors for all listed Umbraco repositories, /// Gets data for all GitHub contributors for all listed Umbraco repositories,
/// excluding the GitHub IDs of the HQ contributors from the text file list /// excluding the GitHub IDs of the HQ contributors from the text file list
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public ActionResult GitHubGetContributorsResult() public ActionResult GitHubGetContributorsResult(bool force = false)
{ {
var model = new GitHubContributorsModel(); var model = new GitHubContributorsModel();
model.Contributors = new List<GitHubCachedGlobalContributorModel>();
try try
{ {
string configPath = Server.MapPath("~/config/githubhq.txt");
if (!System.IO.File.Exists(configPath)) // If the file exists on disk and hasn't expired (AKA not older than one day), we should just load that
if (force == false && System.IO.File.Exists(JsonPath) && System.IO.File.GetLastWriteTimeUtc(JsonPath) >= DateTime.UtcNow.AddDays(-1))
{ {
LogHelper.Debug<GitHubContributorController>("Config file was not found: " + configPath); model.Contributors = GetCachedContributors();
return PartialView("~/Views/Partials/Home/GitHubContributors.cshtml", model); return PartialView("~/Views/Partials/Home/GitHubContributors.cshtml", model);
} }
string[] login = System.IO.File.ReadAllLines(configPath).Where(x => x.Trim() != "").Distinct().ToArray(); try
var contributors = ApplicationContext.ApplicationCache.RuntimeCache.GetCacheItem<List<GitHubGlobalContributorModel>>("UmbracoGitHubContributors", {
() => // Load the contributors via the GitHub API and map to the cached model
{ var contributors = GetContributors().Select(x => new GitHubCachedGlobalContributorModel(x));
var githubController = new GitHubController();
var gitHubContributors = new List<GitHubContributorModel>();
foreach (var repo in Repositories)
{
var response = githubController.GetAllRepoContributors(repo);
if (response.StatusCode == HttpStatusCode.OK &&
response.ResponseStatus == ResponseStatus.Completed)
{
gitHubContributors.AddRange(response.Data);
}
else
{
LogHelper.Warn<IGitHubContributorsModel>(string.Format("Invalid HTTP response for repository {0}", repo));
}
}
var filteredContributors = gitHubContributors // Serialize the contributors to raw JSON
.Where(g => !login.Contains(g.Author.Login)) string rawJson = JsonConvert.SerializeObject(contributors, Formatting.Indented);
.GroupBy(g => g.Author.Id)
.OrderByDescending(c => c.Sum(g => g.Total));
List<GitHubGlobalContributorModel> temp = new List<GitHubGlobalContributorModel>(); // Save the JSON to disk
System.IO.File.WriteAllText(JsonPath, rawJson, Encoding.UTF8);
foreach (var group in filteredContributors) model.Contributors = contributors.ToList();
{ }
temp.Add(new GitHubGlobalContributorModel(group)); catch (Exception ex)
} {
// Log the error so we can debug it later
LogHelper.Error<GitHubContributorController>("Unable to load GitHub contributors from the GitHub API", ex);
return temp; // Load the contributors from the cache (if we have any)
model.Contributors = GetCachedContributors();
}
}, TimeSpan.FromDays(1));
model.Contributors = contributors;
} }
catch (Exception ex) catch (Exception ex)
{ {
LogHelper.Error<IGitHubContributorsModel>("Could not get GitHub Contributors", ex); // Log the error so we can debug it later
LogHelper.Error<GitHubContributorController>("Unable to load GitHub contributors from the GitHub API", ex);
} }
return PartialView("~/Views/Partials/Home/GitHubContributors.cshtml", model); return PartialView("~/Views/Partials/Home/GitHubContributors.cshtml", model);
} }
public List<GitHubGlobalContributorModel> GetContributors()
{
string configPath = Server.MapPath("~/config/githubhq.txt");
if (!System.IO.File.Exists(configPath))
{
LogHelper.Debug<GitHubContributorController>("Config file was not found: " + configPath);
throw new Exception("Config file was not found: " + configPath);
}
string[] login = System.IO.File.ReadAllLines(configPath).Where(x => x.Trim() != "").Distinct().ToArray();
var githubController = new GitHubController();
var gitHubContributors = new List<GitHubContributorModel>();
foreach (var repo in Repositories)
{
var response = githubController.GetAllRepoContributors(repo);
if (response.StatusCode == HttpStatusCode.OK &&
response.ResponseStatus == ResponseStatus.Completed)
{
gitHubContributors.AddRange(response.Data);
}
else
{
LogHelper.Warn<IGitHubContributorsModel>(string.Format("Invalid HTTP response for repository {0}", repo));
}
}
// filter to only include items from the last year (if we ran 4.6.1 we could have used ToUnixTimeSeconds())
var filteredRange = DateTime.UtcNow.AddYears(-1).Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
foreach (var contrib in gitHubContributors)
{
var contribWeeks = contrib.Weeks.Where(x => x.W >= filteredRange).ToList();
contrib.TotalAdditions = contribWeeks.Sum(x => x.A);
contrib.TotalDeletions = contribWeeks.Sum(x => x.D);
contrib.Total = contribWeeks.Sum(x => x.C);
}
var filteredContributors = gitHubContributors
.Where(g => !login.Contains(g.Author.Login))
.GroupBy(g => g.Author.Id)
.OrderByDescending(c => c.Sum(g => g.Total));
List<GitHubGlobalContributorModel> temp = new List<GitHubGlobalContributorModel>();
foreach (var group in filteredContributors)
{
var contributor = new GitHubGlobalContributorModel(group);
if (contributor.TotalCommits > 0)
{
temp.Add(contributor);
}
}
return temp;
}
} }
} }
@@ -4,6 +4,39 @@ using OurUmbraco.Community.Models;
namespace OurUmbraco.Community.Controllers namespace OurUmbraco.Community.Controllers
{ {
public class GitHubCachedGlobalContributorModel
{
public int AuthorId { get; set; }
public string AuthorLogin { get; set; }
public string AuthorUrl { get; set; }
public string AuthorAvatarUrl { get; set; }
public int TotalCommits { get; set; }
public int TotalAdditions { get; set; }
public int TotalDeletions { get; set; }
public GitHubCachedGlobalContributorModel() { }
public GitHubCachedGlobalContributorModel(GitHubGlobalContributorModel contributor)
{
AuthorId = contributor.Author.Id;
AuthorLogin = contributor.Author.Login;
AuthorUrl = contributor.Author.HtmlUrl;
AuthorAvatarUrl = contributor.Author.AvatarUrl;
TotalCommits = contributor.TotalCommits;
TotalAdditions = contributor.TotalAdditions;
TotalDeletions = contributor.TotalDeletions;
}
}
public class GitHubGlobalContributorModel public class GitHubGlobalContributorModel
{ {
public List<GitHubContributorModel> Items { get; set; } public List<GitHubContributorModel> Items { get; set; }
@@ -60,7 +60,8 @@ namespace OurUmbraco.Community.Controllers
x.CreatedBy.UserIdentifier.ScreenName.ToLowerInvariant().ContainsAny(usernameFilter) == x.CreatedBy.UserIdentifier.ScreenName.ToLowerInvariant().ContainsAny(usernameFilter) ==
false false
&& x.UserMentions.Any(m => m.ScreenName.ContainsAny(usernameFilter)) == false && x.UserMentions.Any(m => m.ScreenName.ContainsAny(usernameFilter)) == false
&& x.Text.ToLowerInvariant().ContainsAny(wordFilter) == false) && x.Text.ToLowerInvariant().ContainsAny(wordFilter) == false
&& x.Text.StartsWith("RT ") == false)
.Take(numberOfResults) .Take(numberOfResults)
.ToArray(); .ToArray();
} }
@@ -5,6 +5,6 @@ namespace OurUmbraco.Community.Models
{ {
public class GitHubContributorsModel : IGitHubContributorsModel public class GitHubContributorsModel : IGitHubContributorsModel
{ {
public List<GitHubGlobalContributorModel> Contributors { get; set; } public List<GitHubCachedGlobalContributorModel> Contributors { get; set; }
} }
} }
@@ -3,13 +3,10 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Linq.Expressions;
using System.Net; using System.Net;
using System.Web;
using System.Web.Hosting; using System.Web.Hosting;
using System.Xml; using System.Xml;
using Examine; using Examine;
using ICSharpCode.SharpZipLib.Zip;
using Newtonsoft.Json; using Newtonsoft.Json;
using Umbraco.Core.Logging; using Umbraco.Core.Logging;
using ZipFile = System.IO.Compression.ZipFile; using ZipFile = System.IO.Compression.ZipFile;
@@ -122,10 +119,36 @@ namespace OurUmbraco.Documentation.Busineslogic.GithubSourcePull
public void Process(string url, string foldername) public void Process(string url, string foldername)
{ {
var zip = Download(url, foldername); var zip = Download(url, foldername);
RemoveExistingDocumentation(RootFolder); var unzippedPath = string.Empty;
var branchAllowed = false;
using (var zipFile = ZipFile.OpenRead(zip))
{
var directory = zipFile.Entries.FirstOrDefault();
if (directory != null)
{
var branch = directory.FullName.Replace("/", string.Empty).Replace("UmbracoDocs-", string.Empty);
branchAllowed = IsBranchWhiteListed(branch);
if (branchAllowed)
{
unzippedPath = RootFolder + Path.DirectorySeparatorChar +
directory.FullName.Replace('/', Path.DirectorySeparatorChar);
if (Directory.Exists(unzippedPath))
//delete the directory we're trying to unzip to
RemoveUnzippedFiles(unzippedPath);
}
}
}
if (branchAllowed == false)
return;
ZipFile.ExtractToDirectory(zip, RootFolder); ZipFile.ExtractToDirectory(zip, RootFolder);
var unzippedPath = RootFolder + "\\UmbracoDocs-StarterkitLessons\\"; RemoveUnzippedFiles(RootFolder, ignoreDirectories: new List<string> { unzippedPath });
foreach (var directory in new DirectoryInfo(unzippedPath).GetDirectories()) foreach (var directory in new DirectoryInfo(unzippedPath).GetDirectories())
Directory.Move(directory.FullName, RootFolder + "\\" + directory.Name); Directory.Move(directory.FullName, RootFolder + "\\" + directory.Name);
foreach (var file in new DirectoryInfo(unzippedPath).GetFiles()) foreach (var file in new DirectoryInfo(unzippedPath).GetFiles())
@@ -139,6 +162,25 @@ namespace OurUmbraco.Documentation.Busineslogic.GithubSourcePull
ExamineManager.Instance.IndexProviderCollection["documentationIndexer"].RebuildIndex(); ExamineManager.Instance.IndexProviderCollection["documentationIndexer"].RebuildIndex();
} }
private bool IsBranchWhiteListed(string branch)
{
var xmlNodeList = Configuration.SelectNodes("//allowedBranches");
if (xmlNodeList == null || xmlNodeList.Count <= 0)
return false;
var node = xmlNodeList[0];
if (string.IsNullOrWhiteSpace(node.InnerText))
return false;
var allowedBranches = node.InnerText.Split(',');
var isBranchWhitelisted = allowedBranches.Any(allowedBranch => allowedBranch.Equals(branch, StringComparison.InvariantCultureIgnoreCase));
if (isBranchWhitelisted == false)
LogHelper.Warn<ZipDownloader>(string.Format("The branch {0} is not allowed in githubpull.config, will not process documentation any further", branch));
return isBranchWhitelisted;
}
public void BuildSitemap(string foldername) public void BuildSitemap(string foldername)
{ {
var folder = new DirectoryInfo(Path.Combine(RootFolder, foldername)); var folder = new DirectoryInfo(Path.Combine(RootFolder, foldername));
@@ -158,7 +200,7 @@ namespace OurUmbraco.Documentation.Busineslogic.GithubSourcePull
public List<SiteMapItem> directories { get; set; } public List<SiteMapItem> directories { get; set; }
//public string url => $"http://localhost:24292/documentation{this.path}/?altTemplate=Lesson"; //public string url => $"http://localhost:24292/documentation{this.path}/?altTemplate=Lesson";
public string url public string url
{ {
get get
@@ -181,7 +223,7 @@ namespace OurUmbraco.Documentation.Busineslogic.GithubSourcePull
directories = list, directories = list,
hasChildren = dir.GetDirectories().Any() hasChildren = dir.GetDirectories().Any()
}; };
foreach (var child in dir.GetDirectories().Where(x => x.Name != "images")) foreach (var child in dir.GetDirectories().Where(x => x.Name != "images"))
{ {
list.Add(GetFolderStructure(child, rootPath, level + 1)); list.Add(GetFolderStructure(child, rootPath, level + 1));
@@ -452,21 +494,35 @@ namespace OurUmbraco.Documentation.Busineslogic.GithubSourcePull
return path; return path;
} }
private static void RemoveExistingDocumentation(string folder) private static void RemoveUnzippedFiles(string folder, List<string> ignoreDirectories = null)
{ {
if (Directory.Exists(folder)) if (Directory.Exists(folder))
{ {
foreach (var directory in Directory.GetDirectories(folder)) foreach (var directory in Directory.GetDirectories(folder))
Retry.Do(() => Directory.Delete(directory, true), TimeSpan.FromSeconds(1), 5); {
if (ignoreDirectories == null || ignoreDirectories.Any() == false)
{
//there are no ignores, so proceed to delete it
Retry.Do(() => Directory.Delete(directory, true), TimeSpan.FromSeconds(1), 5);
}
else
{
foreach (var ignoreDirectory in ignoreDirectories)
{
if (ignoreDirectory.TrimEnd('\\').Equals(directory.TrimEnd('\\'),
StringComparison.InvariantCultureIgnoreCase) == false)
{
//path is NOT in the ignore list, so proceed to delete it
Retry.Do(() => Directory.Delete(directory, true), TimeSpan.FromSeconds(1), 5);
}
}
}
}
foreach (var mdfile in Directory.GetFiles(folder, "*.md")) foreach (var mdfile in Directory.GetFiles(folder, "*.md"))
Retry.Do(() => File.Delete(mdfile), TimeSpan.FromSeconds(1), 5); Retry.Do(() => File.Delete(mdfile), TimeSpan.FromSeconds(1), 5);
} }
else
{
Directory.CreateDirectory(folder);
}
} }
private readonly Events _events = new Events(); private readonly Events _events = new Events();
@@ -1,4 +1,5 @@
using System.IO; using System;
using System.IO;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using MarkdownDeep; using MarkdownDeep;
@@ -85,7 +86,7 @@ namespace OurUmbraco.Documentation.Busineslogic
//Need to ensure we dont append the image links as they 404 if we add altTemplate //Need to ensure we dont append the image links as they 404 if we add altTemplate
if (AppendAltLessonLink && rawUrl.StartsWith("images/") == false) if (AppendAltLessonLink && rawUrl.StartsWith("images/") == false)
{ {
return mdUrlTag.Replace(rawUrl, $"{rawUrl.EnsureNoDotsInUrl()}?altTemplate=Lesson"); return mdUrlTag.Replace(rawUrl, string.Format("{0}?altTemplate=Lesson", rawUrl.EnsureNoDotsInUrl()));
} }
return mdUrlTag.Replace(rawUrl, rawUrl.EnsureNoDotsInUrl()); return mdUrlTag.Replace(rawUrl, rawUrl.EnsureNoDotsInUrl());
+13 -1
View File
@@ -123,7 +123,7 @@ FETCH NEXT @count ROWS ONLY";
/// </summary> /// </summary>
/// <param name="category"></param> /// <param name="category"></param>
/// <returns></returns> /// <returns></returns>
public int GetAllTopicsCount(int category = -1) public int GetAllTopicsCount(int category = -1, bool unsolved = false, bool noreplies = false)
{ {
const string sql1 = @"SELECT COUNT(*) as forumTopicCount const string sql1 = @"SELECT COUNT(*) as forumTopicCount
FROM forumTopics FROM forumTopics
@@ -135,6 +135,18 @@ LEFT OUTER JOIN umbracoNode u2 ON (forumTopics.memberId = u2.id AND u2.nodeObjec
var sql = (category > 0 ? sqlic : sqlix); var sql = (category > 0 ? sqlic : sqlix);
if (unsolved)
if (sql.Contains("WHERE"))
sql = sql + " AND answer = 0";
else
sql = sql + " WHERE answer = 0";
if (noreplies)
if (sql.Contains("WHERE"))
sql = sql + " AND replies = 0";
else
sql = sql + " WHERE replies = 0";
return _databaseContext.Database.ExecuteScalar<int>(sql, new { category = category }); return _databaseContext.Database.ExecuteScalar<int>(sql, new { category = category });
} }