67 Commits

Author SHA1 Message Date
Per Ploug 89bb8eb3f4 too much dollar 2017-06-07 08:04:11 +02:00
Per Ploug 6bc5fcad99 Merge remote-tracking branch 'refs/remotes/origin/master' into lesson-documentation-controller 2017-06-07 07:57:12 +02:00
Per Ploug 04bcf16d33 Merge pull request #113 from umbraco/lesson-documentation-controller
Lesson documentation controller
2017-06-07 07:42:50 +02:00
Per Ploug 76752f9bd8 Merge branch 'master' into lesson-documentation-controller 2017-06-07 07:42:41 +02:00
Per Ploug 29d5d293c4 api controller for serving help docs 2017-06-07 07:40:06 +02:00
Sebastiaan Janssen c66e9d208b Merge pull request #109 from emmagarland/githubcontributors
Github contributors list
2017-06-05 20:57:11 +02:00
Emma Garland 7808a20be7 Reverted additions logic 2017-06-05 16:50:43 +01:00
Emma Garland 463ebcaa66 Additions and deletions plural 2017-06-05 16:49:04 +01:00
Emma Garland 2fe55431a0 Contributions plural logic 2017-06-05 16:46:51 +01:00
Emma Garland 0a59d09d81 Moved author title 2017-06-05 16:40:55 +01:00
Warren Buckley 9c4d1baa52 Some more docs to the oh so lovely switch statement 2017-06-05 16:37:25 +01:00
Emma Garland 7ebb26840f Merge remote-tracking branch 'upstream/master' into githubcontributors
# Conflicts:
#	OurUmbraco.Site/OurUmbraco.Site.csproj
#	OurUmbraco.Site/Views/Partials/Community/Home.cshtml
#	OurUmbraco.Site/Views/Partials/Community/Scripts.cshtml
#	OurUmbraco/OurUmbraco.csproj
2017-06-05 16:28:48 +01:00
Warren Buckley ab3603318a Lovely swtich case for now - to give section & tree help context info 2017-06-05 16:20:13 +01:00
Emma Garland ac33beeba9 Smooth transitions and styling for additions and deletions 2017-06-05 16:13:34 +01:00
Emma Garland 87a65f0416 Moved model into new file 2017-06-05 15:57:04 +01:00
Emma Garland 25903c34c6 Comments updated and weeks additions and deletions logic added 2017-06-05 15:56:37 +01:00
Per Ploug 85b7243186 changed branch to WIP Branch for demo 2017-06-05 16:56:03 +02:00
Emma Garland 61cbdeb96b Updated comments on the API methods 2017-06-05 14:15:07 +01:00
Emma Garland 8ab087b23f Updated wording for default branches 2017-06-05 14:11:03 +01:00
Emma Garland e39043af44 Added sizing for the avatar 2017-06-05 13:59:03 +01:00
Emma Garland 2465d4ceb8 Contribute to Umbraco link 2017-06-05 13:45:19 +01:00
Emma Garland 8bf89fdf37 Updated styling and listing of repositories 2017-06-05 13:44:27 +01:00
Emma Garland 89f6f60c96 New window 2017-06-05 13:39:28 +01:00
Emma Garland 1572080976 Updated content to list the Umbraco repositoriies to contribute to 2017-06-05 13:38:31 +01:00
Emma Garland 03de29ebd9 removed github member 2017-06-05 13:26:56 +01:00
Emma Garland 055aea9334 Updated styling with margin right removed and media queries to show or hide different numbers of github users 2017-06-05 13:18:59 +01:00
Emma Garland 06d31b36a6 Updated css and html for github contributors, and updated list of contributors 2017-06-05 12:46:06 +01:00
Sebastiaan Janssen 440084e832 Merge pull request #107 from abjerner/master
Added a new section to the "Community" page listing Umbraco events from Meetup.com
2017-06-05 13:41:30 +02:00
Emma Garland 7abe6161d6 Added more HQ exclusions and reformatted 2017-06-05 12:28:40 +01:00
Emma Garland 576b1bcf2e Load more button now functional 2017-06-05 10:48:52 +01:00
Emma Garland 593d0c31fa HQ exclusion list 2017-06-05 10:10:37 +01:00
Emma Garland 09ed061c9b Now combines more repos 2017-06-05 09:54:59 +01:00
Emma Garland 9b67f4cebf Ordered correctly 2017-06-05 09:05:58 +01:00
Emma Garland b8571f56a6 Updated model to use new method call with accurate commit information 2017-06-05 09:01:07 +01:00
Anders Bjerner 55b2bcae63 Slightly adjusting the list so it still looks okay with an odd number of events 2017-06-05 09:47:15 +02:00
Anders Bjerner 1331c2200e Added new user groups to the configuration file 2017-06-05 09:46:25 +02:00
Emma Garland 3a27201bed Updated sass styling for the avatars 2017-06-04 23:40:49 +01:00
Emma Garland 9a03d09c04 Green header colour as per header 2017-06-04 23:05:48 +01:00
Anders Bjerner ad900861da Updated the implementation
- We can now show logo (or image really) of the group responsible for each event
- Only the first event of each group are shown in the list
- A "NEAR YOU" label is now shown instead of the distance (the location of the group is used as fallback if no venue is specified)
2017-06-04 23:43:32 +02:00
Emma Garland 9f127239ec Updated gulp-imagein version and now successfully compiles 2017-06-04 22:10:31 +01:00
Emma Garland ae555f4130 Wording update 2017-06-04 21:16:18 +01:00
Emma Garland 0c25c1529d Updated to use main Umbraco commits 2017-06-04 20:18:33 +01:00
Warren Buckley efc11c1f40 Revert config - as it expects it to be master branch in other places in the code base at the moment 2017-06-04 20:06:49 +01:00
Warren Buckley eabe640ebf Merge branch 'lesson-documentation-controller' of https://github.com/umbraco/OurUmbraco into lesson-documentation-controller 2017-06-04 20:03:16 +01:00
Warren Buckley d9de0447f5 Update the path to WIP PR Docs branch so we can pull down the MD files 2017-06-04 20:02:59 +01:00
Per Ploug 25858eb870 added method for pulling steps for lessons 2017-06-04 20:58:33 +02:00
Warren Buckley dfb728655f Tiny CSS changes 2017-06-04 19:58:10 +01:00
Warren Buckley 614c4f2d36 Super basic CSS styling 2017-06-04 17:25:24 +01:00
Emma Garland 91d3c6c717 Border and url fix 2017-06-04 17:15:51 +01:00
Emma Garland b235ed168a Inline styles (temp) 2017-06-04 17:12:39 +01:00
Emma Garland b9d5354cc7 GitHub contribution numbers 2017-06-04 16:58:25 +01:00
Warren Buckley 768525a0c7 Ensure we sort by the super magical switch sort int property on the object 2017-06-04 16:54:25 +01:00
Emma Garland 829693c410 Added new styles and classes - sass to be accessed 2017-06-04 16:49:57 +01:00
Sebastiaan Janssen a16c9f1c6c Merge pull request #108 from umbraco/temp-new-starterkit-download
Serve a default starter kit if the version is higher than 7.6.4
2017-06-04 17:48:15 +02:00
Niels Hartvig 6242eed778 Serve a default starter kit if the version is higher than 7.6.4 2017-06-04 17:44:47 +02:00
Warren Buckley 284ca67dd3 Adds trailing slash to ensure all links work as expected when we start off at index.md 2017-06-04 16:40:51 +01:00
Warren Buckley 706c793cc2 Ensure we do not append the altLink to any images as it blows up if we do 2017-06-04 16:38:01 +01:00
Emma Garland 9799071d04 Initial addition of GitHub contributors code 2017-06-04 16:19:21 +01:00
Warren Buckley 492a3e5a8d Init API Controller to Query partial part of the MD Docs tree & WIP for the markdown alt template 2017-06-04 16:07:14 +01:00
Anders Bjerner c6de48c8e2 Added a new section to the "Community" page listing Umbraco events from Meetup.com 2017-06-04 17:02:41 +02:00
Warren Buckley aea3c0a696 Fix OurUmbraco.Site project for loading for people who just have VS17 installed 2017-06-04 13:12:11 +01:00
Sebastiaan Janssen 2fcd7f3911 Better gulp runner 2017-06-04 12:05:57 +02:00
Shannon Deminick 8c6f03f257 Merge pull request #97 from dampee/our-437-edit-link-github-casing
OUR-437 fix casing of md file in case incoming URL has incorrect casing
2017-05-16 14:00:08 +10:00
Shannon 8a24fc60ca fixes the sorting of retreving wiki files 2017-05-15 19:22:16 +10:00
Shannon 1beedba67d Fixes U4-9887 Uses new OUR endpoint for package installation when a package has mixed formats 2017-05-11 14:02:49 +10:00
hartvig 16233f4856 Merge pull request #104 from umbraco/remove-annoying-gif
Remove annoying gif :)
2017-05-04 11:46:59 +02:00
Damiaan Peeters 916a5dc065 OUR-437 fix casing of md file in case incoming URL has incorrect casing 2017-01-26 00:13:17 +01:00
36 changed files with 1363 additions and 111 deletions
+1
View File
@@ -66,3 +66,4 @@ OurUmbraco.Site/App_Data/Documentation/
OurUmbraco.Site/App_Data/NotificationTest/
build/tools/node*
wwwcache/
build/toolsnode.js.*/
+14 -14
View File
@@ -4,24 +4,24 @@
"description": "Umbraco Our gulpjs config",
"main": "gulpfile.js",
"private": true,
"dependencies": {
},
"dependencies": {},
"devDependencies": {
"gulp": "^3.9.1",
"gulp-autoprefixer": "^3.1.0",
"gulp-clean": "0.3.x",
"gulp-combine-media-queries": "0.2.x",
"gulp-concat": "2.2.x",
"gulp-imagemin": "3.3.x",
"gulp-jshint": "^2.0.4",
"gulp-minify-css": "1.1.x",
"gulp-rename": "1.2.x",
"gulp-sass": "^2.2.0",
"gulp-svgmin": "0.4.x",
"gulp-uglify": "^1.5.3",
"gulp-util": "3.0.x",
"gulp-watch": "0.6.x",
"gulp-minify-css": "1.1.x",
"gulp-sass": "^2.2.0",
"gulp-combine-media-queries": "0.2.x",
"gulp-imagemin": "0.6.x",
"gulp-autoprefixer": "^3.1.0",
"gulp-uglify": "^1.5.3",
"gulp-jshint": "2.0.0",
"gulp-concat": "2.2.x",
"jshint-stylish": "0.2.x",
"gulp-clean": "0.3.x",
"gulp-svgmin": "0.4.x",
"gulp-rename": "1.2.x"
"jshint": "^2.9.4",
"jshint-stylish": "0.2.x"
},
"scripts": {
"test": "gulp build --verbose"
@@ -0,0 +1,94 @@
#github-contributors {
&:not(.all) {
.contributor {
&:nth-child(n+17) {
display: none;
}
@media (max-width: $md) {
&:nth-child(n+13) {
display: none;
}
}
@media (max-width: $xs) {
&:nth-child(n+10) {
display: none;
}
}
}
}
&.all {
.button {
display: none;
}
}
.loadmore {
margin: 20px auto;
width: 100%;
text-align: center;
}
}
.github-contributors small.link-list {
font-style: italic;
font-weight: normal;
text-transform: none;
}
.contributor {
margin-bottom: 15px;
.avatar {
position: relative;
flex: 0 0 23%;
margin-right: 20px;
@media (min-width: $md) {
flex: 0 0 15%;
}
img {
border: 3px solid #98d768;
width: 100%;
max-width: 112px;
height: auto;
}
}
.counts {
position: absolute;
top: 2px;
left: 2px;
right: 2px;
text-align: center;
color: #fff;
font-size: 12px;
line-height: 12px;
background: rgba(0,0,0,0.25);
border-radius: 50%;
bottom: 6px;
padding-top: 23px;
opacity: 0;
transition: opacity 0.25s;
}
&:hover .counts {
opacity: 1;
}
.contrib-count {
position: absolute;
left: 25px;
bottom: 0px;
text-align: center;
right: 25px;
color: #425a2e;
font-weight: bold;
background: darken($color-our, 4%);
border-radius: 15px;
z-index: 5;
}
}
+1 -1
View File
@@ -60,7 +60,7 @@
@import 'sections/forum';
@import 'sections/people';
@import 'sections/events';
@import 'sections/contributors';
/**
/* Pages
+18
View File
@@ -224,6 +224,18 @@
<HintPath>..\packages\semver.1.1.2\lib\net451\Semver.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Skybrud.Essentials, Version=1.0.8.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Skybrud.Essentials.1.0.8\lib\net45\Skybrud.Essentials.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Skybrud.Social.Core, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Skybrud.Social.Core.1.0.0-beta9\lib\net45\Skybrud.Social.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Skybrud.Social.Meetup, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Skybrud.Social.Meetup.1.0.0-beta002\lib\net45\Skybrud.Social.Meetup.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLCE4Umbraco, Version=1.0.6274.27357, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\UmbracoCms.Core.7.5.11\lib\SQLCE4Umbraco.dll</HintPath>
<Private>True</Private>
@@ -464,6 +476,7 @@
<SubType>Designer</SubType>
</Content>
<Content Include="config\formHandlers.config" />
<Content Include="config\githubhq.txt" />
<Content Include="config\githubpull.config" />
<Content Include="config\grid.editors.config.js" />
<Content Include="config\Lang\cs-CZ.user.xml" />
@@ -485,6 +498,7 @@
<Content Include="config\Lang\sv-SE.user.xml" />
<Content Include="config\Lang\zh-CN.user.xml" />
<Content Include="config\log4net.config" />
<Content Include="config\MeetupUmbracoGroups.txt" />
<Content Include="config\Notification.config" />
<Content Include="config\restExtensions.config" />
<Content Include="config\Skinning.config" />
@@ -4330,6 +4344,9 @@
<Content Include="Views\Partials\Grid\Bootstrap3-Fluid.cshtml" />
<Content Include="Views\Partials\Grid\Bootstrap2.cshtml" />
<Content Include="Views\Partials\Grid\Bootstrap2-Fluid.cshtml" />
<Content Include="Views\Lesson.cshtml" />
<Content Include="Views\Partials\Home\GitHubContributors.cshtml" />
<Content Include="Views\Partials\Home\Meetups.cshtml" />
<None Include="web.Debug.config">
<DependentUpon>web.config</DependentUpon>
</None>
@@ -4359,6 +4376,7 @@
<VSToolsPath Condition="exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v11.0\WebApplications\Microsoft.WebApplication.targets')">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v11.0</VSToolsPath>
<VSToolsPath Condition="exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v12.0\WebApplications\Microsoft.WebApplication.targets')">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v12.0</VSToolsPath>
<VSToolsPath Condition="exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v14.0\WebApplications\Microsoft.WebApplication.targets')">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v14.0</VSToolsPath>
<VSToolsPath Condition="exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v15.0\WebApplications\Microsoft.WebApplication.targets')">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v15.0</VSToolsPath>
</PropertyGroup>
<PropertyGroup>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
+54
View File
@@ -0,0 +1,54 @@
@using OurUmbraco.Documentation.Busineslogic
@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
Layout = null;
var path = HttpContext.Current.Items[MarkdownLogic.MarkdownPathKey].ToString();
var ml = new MarkdownLogic(path) { PrefixLinks = false, AppendAltLessonLink = true };
var markdown = ml.DoTransformation();
}
<html>
<head>
<title></title>
<link href="https://fonts.googleapis.com/css?family=Asap:400,700,400italic,700italic" type="text/css" rel="stylesheet"/>
<style>
body {
font-family: Asap, sans-serif;
}
code {
background-color: #eeeeee ;
padding: 5px;
}
pre {
word-wrap: break-word;
white-space: pre-wrap;
}
pre > code {
display: block;
}
img {
max-width: 90%;
}
blockquote {
border-left: 4px solid #ddd;
padding: 1px 15px;
color: #777;
background: #efefef ;
margin: 0;
}
</style>
</head>
<body>
<div>
@Html.Raw(markdown)
</div>
</body>
</html>
@@ -1,5 +1,6 @@
@using OurUmbraco.Our.Models
@inherits OurUmbracoTemplatePage
@using Skybrud.Social.Meetup.Models.Events
@inherits OurUmbracoTemplatePage
@{
var homeNotificationText = Model.Content.GetPropertyValue<string>("homeOnlyBanner");
var showHomeNotification = string.IsNullOrWhiteSpace(homeNotificationText) == false;
@@ -39,7 +40,7 @@
<!-- Search end -->
<style>
.bannertext p{
.bannertext p {
line-height: 1.4rem;
}
</style>
@@ -59,6 +60,8 @@
@if (Members.IsLoggedIn())
{
@ForumActivity()
@Meetups()
@GitHubContributors()
@TwitterSearch()
@Html.Partial("home/documentation")
}
@@ -66,6 +69,8 @@ else
{
@Html.Partial("home/documentation")
@ForumActivity()
@Meetups()
@GitHubContributors()
@TwitterSearch()
}
@@ -125,4 +130,62 @@ else
</div>
</div>
</section>
}
@helper GitHubContributors()
{
<section class="github-contributors forum">
<div class="container">
<div class="row">
<div class="col-md-12">
<h1 class="text-center">GitHub Contributions</h1>
<p>
Contributions to Umbraco GitHub repositories
<small class="link-list">
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/UmbracoDocs" target="_blank" title="UmbracoDocs">UmbracoDocs</a>,
<a href="https://github.com/umbraco/OurUmbraco" target="_blank" title="OurUmbraco">OurUmbraco</a>,
<a href="https://github.com/umbraco/Umbraco.Deploy.Contrib" target="_blank" title="Umbraco.Deploy.Contrib">Umbraco.Deploy.Contrib</a>,
<a href="https://github.com/umbraco/Umbraco.Courier.Contrib" target="_blank" title="Umbraco.Courier.Contrib">Umbraco.Courier.Contrib</a> and
<a href="https://github.com/umbraco/Umbraco.Deploy.ValueConnectors" target="_blank" title="Umbraco.Deploy.ValueConnectors">Umbraco.Deploy.ValueConnectors</a> repos
</small>
</p>
</div>
<div class="col-md-12">
<small>GitHub contributors</small>
</div>
<div class="col-md-12 flex forum-thread" id="github-contributors">
<h2>Loading GitHub contributors...</h2>
</div>
<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>
</div>
</div>
</div>
</section>
}
@helper Meetups() {
<section class="forum">
<div class="container">
<div class="row">
<div class="col-md-12">
<h1 class="text-center">Meetups</h1>
<p>
Upcoming meetups organized by the Umbraco community.
</p>
</div>
<div class="col-md-12">
<small>Upcoming meetups</small>
</div>
<div class="col-md-12 flex" id="meetups">
<h2>Loading meetups...</h2>
</div>
</div>
</div>
</section>
}
@@ -1,17 +1,37 @@
<script type="text/javascript">
$(document).ready(function () {
function loadAllGitHubContributors() {
$('#github-contributors').addClass('all');
}
$(document).ready(function() {
try {
$("#twitter-search").load("@Url.Action("TwitterSearchResult", "TwitterSearch", new { numberOfResults = 6 })");
}
catch (errTwitter) {
$("#twitter-search").load("@Url.Action("TwitterSearchResult", "TwitterSearch", new {numberOfResults = 6})");
} catch (errTwitter) {
console.log("Couldn't load Twitter feed", errTwitter.message);
}
try {
$("#forum-activity").load("@Url.Action("LatestActivity", "LatestActivity", new { numberOfTopics = 6 })");
console.log("@Url.Action("GetEvents", "Meetups")");
$("#meetups").load("@Url.Action("GetEvents", "Meetups")");
console.log('yay');
}
catch (errTwitter) {
console.log("Couldn't load meetups", errTwitter.message);
}
try {
$("#forum-activity").load("@Url.Action("LatestActivity", "LatestActivity", new {numberOfTopics = 6})");
} catch (errForum) {
console.log("Couldn't load latest forum activity", errForum.message);
}
try {
$("#github-contributors").load("@Url.Action("GitHubGetContributorsResult", "GitHubContributor")");
}
catch (errForum) {
console.log("Couldn't load latest forum activity", errForum.message);
console.log("Couldn't load latest GitHub contributor activity", errForum.message);
}
});
</script>
@@ -0,0 +1,35 @@
@model OurUmbraco.Community.Models.GitHubContributorsModel
@if (Model.Contributors.Any())
{
foreach (var contributor in Model.Contributors)
{
var author = contributor.Author;
if (author != null)
{
<a href="@author.HtmlUrl" class="contributor" target="_blank" title="@author.Login">
<div class="avatar">
<img alt="@author.Login" src="@author.AvatarUrl&s=112" />
<span class="contrib-count" title="@(contributor.TotalCommits + " " + (contributor.TotalCommits == 1 ? "contribution" : "contributions"))">
@contributor.TotalCommits
</span>
<div class="counts">
Additions<br />
<strong>@contributor.TotalAdditions</strong><br />
<br />
Deletions<br />
<strong>@contributor.TotalDeletions</strong>
</div>
</div>
</a>
}
}
<div class="loadmore">
<a class="button transparent" href="#" onclick="loadAllGitHubContributors(); return false;">Load more</a>
</div>
}
else
{
<h2>Could not load recent GitHub contributors.</h2>
}
@@ -0,0 +1,71 @@
@using OurUmbraco.Community.Models
@using Skybrud.Essentials.Locations
@using Skybrud.Essentials.Locations.Extensions
@using Skybrud.Essentials.Security
@inherits UmbracoViewPage<MeetupEventsModel>
@{
// Get a reference to the current member
IPublishedContent member = Members.GetCurrentMember();
// Get the location of the current member (if logged in and a location is present)
EssentialsLocation memberLocation = null;
if (member != null && member.HasValue("latitude") && member.HasValue("longitude")) {
memberLocation = new EssentialsLocation(
member.GetPropertyValue<double>("latitude"),
member.GetPropertyValue<double>("longitude")
);
}
}
@foreach (MeetupItem item in Model.Items) {
double distance = -1;
if (memberLocation != null) {
if (item.Event.HasVenue) {
distance = memberLocation.GetDistance(item.Event.Venue);
} else {
distance = memberLocation.GetDistance(item.Group);
}
}
<a href="@item.Event.Link" class="forum-thread">
@if (item.Group.GroupPhoto != null)
{
<div class="avatar">
<img src="@item.Group.GroupPhoto.ThumbLink" alt="" />
</div>
}
else
{
string fakeHash = SecurityUtils.GetMd5Hash(item.Group.Id + "");
<div class="avatar">
<img src="https://www.gravatar.com/avatar/@fakeHash?s=100&d=mm&r=g&d=retro" alt="" />
</div>
}
<div class="meta">
<div class="forum-thread-text">
@if (distance >= 0 && distance <= 50000) {
//<span style="float: right; color: red;">@String.Format("~{0:N0}", distance / 1000) km</span>
<span style="float: right; color: red; font-weight: bold;" title="Distance: @String.Format("~{0:N0}", distance / 1000) km">NEAR YOU</span>
}
<h3>@item.Event.Name</h3>
<p>@item.Event.Time.DateTime.ToString("MMM d, yyyy") by @item.Group.Name</p>
</div>
</div>
</a>
}
@if (Model.Items.Length % 2 == 1) {
// If there is an odd amount of events, we add a invisible div so the last event doesn't take up the full width
<div class="forum-thread" style="visibility: hidden;"></div>
}
@if (Model.Items.Any() == false) {
<h2>Could not load upcoming meetups.</h2>
}
@@ -10,7 +10,7 @@ NOTES:
* Compression/Combination/Minification is not enabled unless debug="false" is specified on the 'compiliation' element in the web.config
* A new version will invalidate both client and server cache and create new persisted files
-->
<clientDependency version="463511010" fileDependencyExtensions=".js,.css" loggerType="Umbraco.Web.UI.CdfLogger, umbraco">
<clientDependency version="49321111" fileDependencyExtensions=".js,.css" loggerType="Umbraco.Web.UI.CdfLogger, umbraco">
<!--
This section is used for Web Forms only, the enableCompositeFiles="true" is optional and by default is set to true.
@@ -0,0 +1,35 @@
umbracodk
Dutch-Umbraco-User-Group
Australian-Umbraco-Meetups
Kent-Umbraco-Meetup
Sydney-Umbraco-Meetup
Umbraco-Meetup-RheinMain
The-London-Umbraco-Meetup
Denver-Area-Umbraco-Meetup
Auckland-Umbraco-Meetup
Denver-Area-Umbraco-Meetup
Dorset-Umbraco-Meetup
Umbraco-Oxford-Meetup
Madrid-Umbraco-Meetup-Group
Chicago-Umbraco-Meetup
Umbraco
Umbraco-Dev-TC
Goteborg-Umbraco-Meetup
Dublin-Umbraco-Meetup
Umbraco-BA
Manchester-Umbraco-Meetup
Liverpool-Umbraco-Meetup
The-Poland-Umbraco-Meetup
Lisbon-Umbraco-Meetup
Glasgow-Umbraco-Users-Group-GLUUG
PNW-Umbraco-Meetup
Adelaide-Umbraco-Meetup
The-New-York-Umbraco-Meetup
Umbraco-Navi-Mumbai-NET-Meetup
Edinburgh-Umbraco-Users-Group
Stuttgart-Umbraco-Meetup
UmbCardiff
meet-umbraco-the-umbraco-meetup
umBristol
Oslo-Umbraco-Meetup
Orange-County-Umbraco-Web-Technologies
+16
View File
@@ -0,0 +1,16 @@
Aaen
clausjensen
emilwangaa
hartvig
hemraker
madsrasmussen
mikkelhm
nul800sebastiaan
perploug
Shazwazza
simonbusborg
sitereactor
sofietoft
umbracoci
warrenbuckley
zpqrtbnk
+3
View File
@@ -56,6 +56,9 @@
<package id="RestSharp" version="104.1" targetFramework="net4" />
<package id="semver" version="1.1.2" targetFramework="net452" />
<package id="SharpZipLib" version="0.86.0" targetFramework="net452" />
<package id="Skybrud.Essentials" version="1.0.8" targetFramework="net452" />
<package id="Skybrud.Social.Core" version="1.0.0-beta9" targetFramework="net452" />
<package id="Skybrud.Social.Meetup" version="1.0.0-beta002" targetFramework="net452" />
<package id="System.Collections.Immutable" version="1.1.36" targetFramework="net452" />
<package id="System.Reflection.Metadata" version="1.0.21" targetFramework="net452" />
<package id="TweetinviAPI" version="1.2.0" targetFramework="net452" />
+1
View File
@@ -105,6 +105,7 @@
<add key="SpamBlockThreshold" value="90" />
<add key="ValidationSettings:UnobtrusiveValidationMode" value="None" />
<add key="UmbracoStarterKits" value="55E028E3-0C5B-4188-9722-7D14B4BD12C0,69E44BEB-15FF-4CEE-8B64-0A7DAE498657,0B0101F7-9394-48F3-A581-DD3F18480265" />
<add key="UmbracoStarterKitDefault" value="ced954d1-8c0f-4abe-bdda-99e7a787d052"/>
<add key="SlackChannel" value="#our-spam-reports" />
<add key="SlackToken" value="" />
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using OurUmbraco.Community.Models;
using OurUmbraco.Our.Api;
using RestSharp;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Web.Mvc;
namespace OurUmbraco.Community.Controllers
{
public class GitHubContributorController : SurfaceController
{
/// <summary>
/// Repositories to include in the combination of contributions
/// </summary>
private readonly string[] Repositories =
{
"Umbraco-CMS",
"UmbracoDocs",
"OurUmbraco",
"Umbraco.Deploy.Contrib",
"Umbraco.Courier.Contrib",
"Umbraco.Deploy.ValueConnectors"
};
/// <summary>
/// Gets data for all GitHub contributors for all listed Umbraco repositories,
/// excluding the GitHub IDs of the HQ contributors from the text file list
/// </summary>
/// <returns></returns>
public ActionResult GitHubGetContributorsResult()
{
var model = new GitHubContributorsModel();
try
{
string configPath = Server.MapPath("~/config/githubhq.txt");
if (!System.IO.File.Exists(configPath))
{
LogHelper.Debug<GitHubContributorController>("Config file was not found: " + configPath);
return PartialView("~/Views/Partials/Home/GitHubContributors.cshtml", model);
}
string[] login = System.IO.File.ReadAllLines(configPath).Where(x => x.Trim() != "").Distinct().ToArray();
var contributors = ApplicationContext.ApplicationCache.RuntimeCache.GetCacheItem<List<GitHubGlobalContributorModel>>("UmbracoGitHubContributors",
() =>
{
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
.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)
{
temp.Add(new GitHubGlobalContributorModel(group));
}
return temp;
}, TimeSpan.FromDays(1));
model.Contributors = contributors;
}
catch (Exception ex)
{
LogHelper.Error<IGitHubContributorsModel>("Could not get GitHub Contributors", ex);
}
return PartialView("~/Views/Partials/Home/GitHubContributors.cshtml", model);
}
}
}
@@ -0,0 +1,42 @@
using System.Collections.Generic;
using System.Linq;
using OurUmbraco.Community.Models;
namespace OurUmbraco.Community.Controllers
{
public class GitHubGlobalContributorModel
{
public List<GitHubContributorModel> Items { get; set; }
public int Id
{
get { return Author.Id; }
}
public int TotalCommits
{
get { return Items.Sum(x => x.Total); }
}
public int TotalAdditions
{
get { return Items.Sum(x => x.TotalAdditions); }
}
public int TotalDeletions
{
get { return Items.Sum(x => x.TotalDeletions); }
}
public Author Author
{
get { return Items.First().Author; }
}
public GitHubGlobalContributorModel(IEnumerable<GitHubContributorModel> items)
{
Items = items.ToList();
}
}
}
@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using OurUmbraco.Community.Models;
using Skybrud.Essentials.Json.Extensions;
using Skybrud.Social.Meetup;
using Skybrud.Social.Meetup.Models.Events;
using Skybrud.Social.Meetup.Models.Groups;
using Skybrud.Social.Meetup.Responses.Events;
using Skybrud.Social.Meetup.Responses.Groups;
using Umbraco.Core.Logging;
using Umbraco.Web.Mvc;
using Umbraco.Core.Cache;
namespace OurUmbraco.Community.Controllers {
public class MeetupsController : SurfaceController {
public ActionResult GetEvents() {
MeetupEventsModel model = new MeetupEventsModel {
Items = new MeetupItem[0]
};
try {
string configPath = Server.MapPath("~/config/MeetupUmbracoGroups.txt");
if (!System.IO.File.Exists(configPath)) {
LogHelper.Debug<MeetupsController>("Config file was not found: " + configPath);
return PartialView("~/Views/Partials/Home/Meetups.cshtml", model);
}
// Get the alias (urlname) of each group from the config file
string[] aliases = System.IO.File.ReadAllLines(configPath).Where(x => x.Trim() != "").Distinct().ToArray();
model.Items =
ApplicationContext.ApplicationCache.RuntimeCache.GetCacheItem<MeetupItem[]>("UmbracoSearchedMeetups",
() => {
// Initialize a new service instance (we don't specify an API key since we're accessing public data)
MeetupService service = new MeetupService();
List<MeetupItem> items = new List<MeetupItem>();
foreach (string alias in aliases) {
try {
// Get information about the group
MeetupGroup group = service.Groups.GetGroup(alias).Body;
if (group.JObject.HasValue("next_event")) {
string nextEventId = group.JObject.GetString("next_event.id");
// Make the call to the Meetup.com API to get upcoming events
MeetupGetEventsResponse res = service.Events.GetEvents(alias);
// Get the next event(s)
MeetupEvent nextEvent = res.Body.FirstOrDefault(x => x.Id == nextEventId);
// Append the first event of the group
if (nextEvent != null) items.Add(new MeetupItem(group, nextEvent));
}
} catch (Exception ex) {
LogHelper.Error<MeetupsController>("Could not get events from meetup.com for group with alias: " + alias, ex);
}
}
return items.OrderBy(x => x.Event.Time).ToArray();
}, TimeSpan.FromMinutes(30));
} catch (Exception ex) {
LogHelper.Error<MeetupsController>("Could not get events from meetup.com", ex);
}
return PartialView("~/Views/Partials/Home/Meetups.cshtml", model);
}
}
}
@@ -0,0 +1,10 @@
using System.Collections.Generic;
using OurUmbraco.Community.Controllers;
namespace OurUmbraco.Community.Models
{
public class GitHubContributorsModel : IGitHubContributorsModel
{
public List<GitHubGlobalContributorModel> Contributors { get; set; }
}
}
@@ -0,0 +1,117 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace OurUmbraco.Community.Models
{
[DataContract]
public class GitHubContributorModel : IGitHubContributorModel
{
private List<Week> _weeks;
public int Total { get; set; }
public int TotalAdditions { get; set; }
public int TotalDeletions { get; set; }
[DataMember(Name = "weeks")]
public List<Week> Weeks
{
get { return _weeks; }
set
{
_weeks = value;
int totalAdditions = 0;
int totalDeletions = 0;
foreach (var week in _weeks)
{
totalDeletions += week.D;
totalAdditions += week.A;
}
TotalAdditions = totalAdditions;
TotalDeletions = totalDeletions;
}
}
public Author Author { get; set; }
}
[DataContract]
public class Week
{
/// <summary>
/// Timestamp
/// </summary>
public int W { get; set; }
/// <summary>
/// Additions
/// </summary>
public int A { get; set; }
/// <summary>
/// Deletions
/// </summary>
public int D { get; set; }
/// <summary>
/// Commits
/// </summary>
public int C { get; set; }
}
[DataContract]
public class Author
{
public string Login { get; set; }
public int Id { get; set; }
[DataMember(Name = "avatar_url")]
public string AvatarUrl { get; set; }
[DataMember(Name = "gravatar_id")]
public string GravatarId { get; set; }
public string Url { get; set; }
[DataMember(Name = "html_url")]
public string HtmlUrl { get; set; }
[DataMember(Name = "followers_url")]
public string FollowersUrl { get; set; }
[DataMember(Name = "following_url")]
public string FollowingsUrl { get; set; }
[DataMember(Name = "gists_url")]
public string GistsUrl { get; set; }
[DataMember(Name = "starred_url")]
public string StarredUrl { get; set; }
[DataMember(Name = "subscriptions_url")]
public string SubscriptionsUrl { get; set; }
[DataMember(Name = "organizations_url")]
public string OrganizationsUrl { get; set; }
[DataMember(Name = "repos_url")]
public string ReposUrl { get; set; }
[DataMember(Name = "events_url")]
public string EventsUrl { get; set; }
[DataMember(Name = "received_events_url")]
public string ReceivedEventsUrl { get; set; }
public string Type { get; set; }
[DataMember(Name = "site_admin")]
public bool SiteAdmin { get; set; }
}
}
@@ -0,0 +1,6 @@
namespace OurUmbraco.Community.Models
{
public interface IGitHubContributorModel
{
}
}
@@ -0,0 +1,6 @@
namespace OurUmbraco.Community.Models
{
public interface IGitHubContributorsModel
{
}
}
@@ -0,0 +1,9 @@
namespace OurUmbraco.Community.Models {
public class MeetupEventsModel {
public MeetupItem[] Items { get; set; }
}
}
+24
View File
@@ -0,0 +1,24 @@
using Skybrud.Essentials.Locations;
using Skybrud.Social.Meetup.Models.Events;
using Skybrud.Social.Meetup.Models.Groups;
namespace OurUmbraco.Community.Models {
public class MeetupItem {
public MeetupGroup Group { get; set; }
public MeetupEvent Event { get; set; }
public ILocation Location {
get { return Event.HasVenue ? (ILocation) Event.Venue : Group; }
}
public MeetupItem(MeetupGroup group, MeetupEvent ev) {
Group = group;
Event = ev;
}
}
}
@@ -112,12 +112,11 @@ namespace OurUmbraco.Documentation.Busineslogic.GithubSourcePull
FireOnFinish(finishEventArgs);
}
public dynamic DocumentationSiteMap(string folder = "")
public SiteMapItem DocumentationSiteMap(string folder = "")
{
var path = Path.Combine(RootFolder, folder, "sitemap.js");
var json = File.ReadAllText(path);
dynamic documentationSiteMap = JsonConvert.DeserializeObject<dynamic>(json);
return documentationSiteMap;
return JsonConvert.DeserializeObject<SiteMapItem>(json);
}
public void Process(string url, string foldername)
@@ -126,7 +125,7 @@ namespace OurUmbraco.Documentation.Busineslogic.GithubSourcePull
RemoveExistingDocumentation(RootFolder);
ZipFile.ExtractToDirectory(zip, RootFolder);
var unzippedPath = RootFolder + "\\UmbracoDocs-master\\";
var unzippedPath = RootFolder + "\\UmbracoDocs-StarterkitLessons\\";
foreach (var directory in new DirectoryInfo(unzippedPath).GetDirectories())
Directory.Move(directory.FullName, RootFolder + "\\" + directory.Name);
foreach (var file in new DirectoryInfo(unzippedPath).GetFiles())
@@ -143,13 +142,13 @@ namespace OurUmbraco.Documentation.Busineslogic.GithubSourcePull
public void BuildSitemap(string foldername)
{
var folder = new DirectoryInfo(Path.Combine(RootFolder, foldername));
dynamic root = GetFolderStructure(folder, folder.FullName, 0);
var root = GetFolderStructure(folder, folder.FullName, 0);
var serializedRoot = JsonConvert.SerializeObject(root, Newtonsoft.Json.Formatting.Indented);
File.WriteAllText(Path.Combine(folder.FullName, "sitemap.js"), serializedRoot);
}
private class SiteMapItem
public class SiteMapItem
{
public string name { get; set; }
public string path { get; set; }
@@ -157,28 +156,37 @@ namespace OurUmbraco.Documentation.Busineslogic.GithubSourcePull
public int sort { get; set; }
public bool hasChildren { get; set; }
public List<SiteMapItem> directories { get; set; }
//public string url => $"http://localhost:24292/documentation{this.path}/?altTemplate=Lesson";
public string url
{
get
{
return string.Format("https://our.umbraco.org/documentation{0}/?altTemplate=Lesson", this.path);
}
}
}
private SiteMapItem GetFolderStructure(DirectoryInfo dir, string rootPath, int level)
{
var list = new List<SiteMapItem>();
var siteMapItem = new SiteMapItem
{
name = dir.Name.Replace("-", " "),
path = dir.FullName.Substring(rootPath.Length).Replace('\\', '/'),
level = level,
sort = GetSort(dir.Name, level) ?? 100
sort = GetSort(dir.Name, level) ?? 100,
directories = list,
hasChildren = dir.GetDirectories().Any()
};
if (dir.GetDirectories().Any() == false)
return siteMapItem;
var list = new List<SiteMapItem>();
foreach (var child in dir.GetDirectories().Where(x => x.Name != "images"))
{
list.Add(GetFolderStructure(child, rootPath, level + 1));
}
siteMapItem.hasChildren = true;
siteMapItem.directories = list.OrderBy(x => x.sort).ToList();
return siteMapItem;
@@ -11,6 +11,7 @@ namespace OurUmbraco.Documentation.Busineslogic
public MarkdownLogic(string filePath)
{
_filePath = filePath;
AppendAltLessonLink = false;
}
public const string VersionSession = "DocumentationVersion";
@@ -28,6 +29,8 @@ namespace OurUmbraco.Documentation.Busineslogic
public bool PrefixLinks { get; set; }
public bool AppendAltLessonLink { get; set; }
public string DoTransformation()
{
if (File.Exists(_filePath))
@@ -79,6 +82,11 @@ namespace OurUmbraco.Documentation.Busineslogic
else
mdUrlTag.TrimEnd('/');
//Need to ensure we dont append the image links as they 404 if we add altTemplate
if (AppendAltLessonLink && rawUrl.StartsWith("images/") == false)
{
return mdUrlTag.Replace(rawUrl, $"{rawUrl.EnsureNoDotsInUrl()}?altTemplate=Lesson");
}
return mdUrlTag.Replace(rawUrl, rawUrl.EnsureNoDotsInUrl());
}
@@ -0,0 +1,280 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using OurUmbraco.Documentation.Busineslogic.GithubSourcePull;
using OurUmbraco.Documentation.Models;
using Umbraco.Core;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
using System.Web;
using OurUmbraco.Documentation.Busineslogic;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace OurUmbraco.Documentation.Controllers
{
[PluginController("Documentation")]
public class LessonsController : UmbracoApiController
{
/// <summary>
///
/// </summary>
/// <param name="path">The path in the documentation folder structure that you wish to start from & list descendants</param>
/// <param name="userType">Future Use: Backoffice Usertype requesting lessons</param>
/// <param name="allowedSections">Future Use: AllowedSections of BackOffice User</param>
/// <param name="lang">Future Use: Backoffice Users langunage</param>
/// <param name="version">Umbraco CMS Version as a string</param>
/// <returns>
/// A partial part of the documentation tree, that lists out folders
/// This is used in the new Starter Kit in conjuction with 'Lessons'
/// </returns>
public List<ZipDownloader.SiteMapItem> GetDocsForPath(string path, string userType, string allowedSections, string lang, string version)
{
//Ensure path is not null & empty
if (string.IsNullOrEmpty(path))
{
var resp = new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent("Path varibale is null or empty"),
ReasonPhrase = "Documentation Path is invalid"
};
throw new HttpResponseException(resp);
}
//Get the documentation Sitemap JS file that lives on disk everytime we fetch & unpack the markdown docs from GitHub
var docs = new ZipDownloader();
//Note: For now the folder param is NOT the folder/subtree but where the JSON file is stored to build up this model
var allDocs = docs.DocumentationSiteMap();
//Split path and ensure we can find each part of the path
//In the array of nested objects
var pathArray = path.Split('/').Where(x => string.IsNullOrEmpty(x) == false).ToArray();
var currentDirectory = allDocs;
for (int i = 0; i < pathArray.Length; i++)
{
var pathPart = "/" + string.Join("/", pathArray.Take(i + 1));
currentDirectory = currentDirectory.directories.First(x => x.path == pathPart);
}
return currentDirectory.directories.OrderBy(x=> x.sort).ToList();
}
/// <summary>
/// Gets Steps (Children of a lesson as rendered HTML from the markdown file)
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public List<LessonStep> GetStepsForPath(string path)
{
var docs = new ZipDownloader();
var rootFolder = global::Umbraco.Core.IO.IOHelper.MapPath("/Documentation/" + path);
var mdFiles = System.IO.Directory.GetFiles(rootFolder, "*.md");
var result = new List<LessonStep>();
foreach(var fpath in mdFiles)
{
var content = System.IO.File.ReadAllText(fpath);
var name = System.IO.Path.GetFileName(path);
var md = new MarkdownLogic(fpath);
var html = md.DoTransformation();
result.Add(new LessonStep() { Name = name, Content = html });
}
return result;
}
/// <summary>
///
/// </summary>
/// <param name="sectionAlias"></param>
/// <param name="treeAlias"></param>
public List<HelpDocument> GetContextHelpDocs(string sectionAlias, string treeAlias)
{
if (sectionAlias.ToLower() == "settings" && treeAlias.ToLower() == "documenttypes")
{
return new List<HelpDocument>
{
new HelpDocument
{
Name = "Defining Content",
Description = "Here you'll find an explanation of how content is defined and quick guide for your first go at it (based on an empty installation).",
Type = HelpDocType.Doc,
Url = "https://our.umbraco.org/documentation/Getting-Started/Data/Defining-content/"
}
};
}
if (sectionAlias.ToLower() == "settings" && (treeAlias.ToLower() == "templates" || treeAlias.ToLower() == "partialviews") )
{
return new List<HelpDocument>
{
new HelpDocument
{
Name = "Templates",
Description = "Templating in Umbraco builds on the concept of Razor Views from asp.net MVC - if you already know this, then you are ready to create your first template - if not, this is a quick and handy guide.",
Type = HelpDocType.Doc,
Url = "https://our.umbraco.org/documentation/Getting-Started/Design/Templates/"
},
new HelpDocument
{
Name = "Basic Razor Syntax",
Description = "Shows how to perform common logical tasks in Razor like if/else, foreach loops, switch statements and using the @ character to separate code and markup.",
Type = HelpDocType.Doc,
Url = "https://our.umbraco.org/documentation/Getting-Started/Design/Templates/basic-razor-syntax"
},
new HelpDocument
{
Name = "Rendering Content",
Description = "The primary task of any template in Umbraco is to render the values of the current page or the result of query against the content cache.",
Type = HelpDocType.Doc,
Url = "https://our.umbraco.org/documentation/Getting-Started/Design/Rendering-Content/"
},
new HelpDocument
{
Name = "Rendering Media",
Description = "Templates can access items in the Media library, to assist in displaying rich content like galleries.",
Type = HelpDocType.Doc,
Url = "https://our.umbraco.org/documentation/Getting-Started/Design/Rendering-Media/"
},
new HelpDocument
{
Name = "Basic Razor Syntax",
Description = "Shows how to perform common logical tasks in Razor like if/else, foreach loops, switch statements and using the @ character to separate code and markup.",
Type = HelpDocType.Doc,
Url = "https://our.umbraco.org/documentation/Getting-Started/Design/Templates/basic-razor-syntax"
},
new HelpDocument
{
Name = "View/Razor Examples",
Description = "Lots of examples of using various techniques to render data in a view",
Type = HelpDocType.Doc,
Url = "https://our.umbraco.org/documentation/Reference/Templating/Mvc/examples"
}
};
}
if (sectionAlias.ToLower() == "media")
{
return new List<HelpDocument>
{
new HelpDocument
{
Name = "Creating Media",
Description = "Media in Umbraco is handled in much the same way as content. Instead of defining Document Types you define Media Types that act as the base for media items.",
Type = HelpDocType.Doc,
Url = "https://our.umbraco.org/documentation/Getting-Started/Data/Creating-Media/"
}
};
}
if (sectionAlias.ToLower() == "developer" && treeAlias.ToLower() == "datatypes")
{
return new List<HelpDocument>
{
new HelpDocument
{
Name = "Data-Types",
Description = "A Data Type defines the type of input for a property. So when adding a property (on Document Types, Media Types and Members) when selecting the Type you are selecting a Data Type. There are a number of preconfigured Data Types available in Umbraco and more can be added in the Developer section.",
Type = HelpDocType.Doc,
Url = "https://our.umbraco.org/documentation/Getting-Started/Data/Data-Types/"
},
new HelpDocument
{
Name = "Property Editors",
Description = "Extend Umbraco with your own property editors ",
Url = "https://our.umbraco.org/documentation/Extending/Property-Editors/",
Type = HelpDocType.Doc
}
};
}
if (sectionAlias.ToLower() == "member")
{
return new List<HelpDocument>
{
new HelpDocument
{
Name = "Members",
Description = "Members are used for registering and authenticating external users of an Umbraco installation (ie. forum members, intranet users and so forth). Unlike with Document Types and Media Types everything is done in the Members section both defining and creating, and editing members.",
Type = HelpDocType.Doc,
Url = "https://our.umbraco.org/documentation/Getting-Started/Data/Members/"
}
};
}
if (sectionAlias.ToLower() == "developer")
{
return new List<HelpDocument>
{
new HelpDocument
{
Name = "Data-Types",
Description = "A Data Type defines the type of input for a property. So when adding a property (on Document Types, Media Types and Members) when selecting the Type you are selecting a Data Type. There are a number of preconfigured Data Types available in Umbraco and more can be added in the Developer section.",
Type = HelpDocType.Doc,
Url = "https://our.umbraco.org/documentation/Getting-Started/Data/Data-Types/"
},
new HelpDocument
{
Name = "Macros",
Description = "A macro is a reusable piece of functionality that you can re-use throughout your site. Macros can be configured with parameters and be inserted into a Rich Text Editor.",
Url = "https://our.umbraco.org/Documentation/Reference/Templating/Macros/",
Type = HelpDocType.Doc
},
new HelpDocument
{
Name = "Xslt",
Description = "XSLT will soon be removed from Umbraco - read how you can transition away from it",
Url = "https://our.umbraco.org/Documentation/Reference/Templating/Macros/Xslt/",
Type = HelpDocType.Doc
}
};
}
//Did not find anything for the combination
return null;
}
}
[DataContract(Name = "lessonStep")]
public class LessonStep
{
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "content")]
public string Content { get; set; }
}
[DataContract(Name = "helpDocument")]
public class HelpDocument
{
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "url")]
public string Url { get; set; }
[DataMember(Name = "description")]
public string Description { get; set; }
[DataMember(Name = "type")]
[JsonConverter(typeof(StringEnumConverter))]
public HelpDocType Type { get; set; }
}
public enum HelpDocType { Doc, Video }
}
@@ -5,6 +5,8 @@ using System.Web;
using OurUmbraco.Documentation.Busineslogic;
using Umbraco.Core;
using Umbraco.Web.Routing;
using System.Collections.Generic;
using System.Globalization;
namespace OurUmbraco.Documentation
{
@@ -29,7 +31,7 @@ namespace OurUmbraco.Documentation
return false;
// kill those old urls
foreach (var s in new []{ "master", "v480" })
foreach (var s in new[] { "master", "v480" })
if (url.StartsWith(mdRoot + "/" + s))
{
url = url.Replace(mdRoot + "/" + s, mdRoot);
@@ -39,7 +41,7 @@ namespace OurUmbraco.Documentation
// find the md file
var mdFilepath = FindMarkdownFile(url);
//return the broken link doc page
var is404 = false;
if (mdFilepath == null)
@@ -48,13 +50,13 @@ namespace OurUmbraco.Documentation
is404 = true;
}
if (mdFilepath == null)
{
{
// clear the published content (that was set by FindContent) to cause a 404, and in
// both case return 'true' because there's no point other finders try to handle the request
contentRequest.PublishedContent = null;
return true;
}
if (is404) contentRequest.SetIs404();
// set the context vars
@@ -70,7 +72,7 @@ namespace OurUmbraco.Documentation
var templateIsSet = contentRequest.TrySetTemplate(altTemplate);
//httpContext.Trace.Write("Markdown Files Handler",
// string.Format("Template changed to: '{0}' is {1}", altTemplate, templateIsSet));
// be happy
return true;
}
@@ -113,7 +115,7 @@ namespace OurUmbraco.Documentation
fpath = string.Concat(HttpRuntime.AppDomainAppPath, relpath, "\\index.md");
if (File.Exists(fpath))
return fpath;
fpath = string.Concat(HttpRuntime.AppDomainAppPath, relpath, "\\readme.md");
if (File.Exists(fpath))
return fpath;
@@ -145,37 +147,94 @@ namespace OurUmbraco.Documentation
string baseUrl = "https://github.com/umbraco/UmbracoDocs/blob/" + branchName;
var docUrl = HttpContext.Current.Items[MarkdownLogic.MarkdownPathKey].ToString();
if (System.IO.File.Exists(docUrl))
//Need to get NEW key as needs to be the original MD filename
//from Github including .md & correct casing of file
//var originalUrl = HttpContext.Current.Items["umbOriginalUrl"].ToString();
string originalUrl;
if (!TryGetExactPath(docUrl, out originalUrl))
{
//Need to get NEW key as needs to be the original MD filename
//from Github including .md & correct casing of file
var originalUrl = HttpContext.Current.Items["umbOriginalUrl"].ToString();
//Ensure beginning part of url is right case for GitHub URL
if (originalUrl.StartsWith("/documentation/", StringComparison.InvariantCultureIgnoreCase))
// don't strip off the leading "/"
originalUrl = originalUrl.Substring("/documentation/".Length - 1);
//If ends with / then it's an index.md file in a folder
if (originalUrl.EndsWith("/"))
{
//Add the word after the /, so it's /index
originalUrl += "index";
}
//Append the .md file extension
docUrl = baseUrl + string.Format("{0}{1}", originalUrl, ".md");
// MD file does not exist on disk - hide edit button
return null;
}
else
// Ensure beginning part of url is right case for GitHub URL
var docFolderPosition = originalUrl.IndexOf(@"\documentation\", StringComparison.InvariantCultureIgnoreCase);
if (docFolderPosition > -1)
{
//MD file does not exist on disk - hide edit button
docUrl = null;
// don't strip off the leading "/"
originalUrl = originalUrl
.Substring(docFolderPosition + @"\documentation\".Length - 1)
.Replace('\\', '/');
}
// If ends with / then it's an index.md file in a folder
if (originalUrl.EndsWith("/"))
{
// Add the word after the /, so it's /index
originalUrl += "index.md";
}
// Append the base and file url together
docUrl = baseUrl + originalUrl;
return docUrl;
}
/// <summary>
/// Gets the exact case used on the file system for an existing file or directory.
/// </summary>
/// <param name="path">A relative or absolute path.</param>
/// <param name="exactPath">The full path using the correct case if the path exists. Otherwise, null.</param>
/// <returns>True if the exact path was found. False otherwise.</returns>
/// <remarks>
/// This supports drive-lettered paths and UNC paths, but a UNC root
/// will be returned in title case (e.g., \\Server\Share).
/// Original from http://stackoverflow.com/a/29578292/97615
/// </remarks>
public static bool TryGetExactPath(string path, out string exactPath)
{
bool result = false;
exactPath = null;
// DirectoryInfo accepts either a file path or a directory path, and most of its properties work for either.
// However, its Exists property only works for a directory path.
DirectoryInfo directory = new DirectoryInfo(path);
if (File.Exists(path) || directory.Exists)
{
var parts = new List<string>();
DirectoryInfo parentDirectory = directory.Parent;
while (parentDirectory != null)
{
FileSystemInfo entry = parentDirectory.EnumerateFileSystemInfos(directory.Name).First();
parts.Add(entry.Name);
directory = parentDirectory;
parentDirectory = directory.Parent;
}
// Handle the root part (i.e., drive letter or UNC \\server\share).
string root = directory.FullName;
if (root.Contains(':'))
{
root = root.ToUpper();
}
else
{
string[] rootParts = root.Split('\\');
root = string.Join("\\", rootParts.Select(part => CultureInfo.CurrentCulture.TextInfo.ToTitleCase(part)));
}
parts.Add(root);
parts.Reverse();
exactPath = Path.Combine(parts.ToArray());
result = true;
}
return result;
}
}
}
}
+27
View File
@@ -0,0 +1,27 @@
using System.Collections.Generic;
using OurUmbraco.Community.Models;
using RestSharp;
namespace OurUmbraco.Our.Api
{
public class GitHubController
{
private const string RepositoryOwner = "Umbraco";
private const string GitHubApiClient = "https://api.github.com";
private const string UserAgent = "OurUmbraco";
/// <summary>
/// Get all contributors from GitHub Umbraco repositories
/// </summary>
/// <param name="repo"></param>
/// <returns></returns>
public IRestResponse<List<GitHubContributorModel>> GetAllRepoContributors(string repo)
{
var client = new RestClient(GitHubApiClient);
var request = new RestRequest(string.Format("/repos/{0}/{1}/stats/contributors", RepositoryOwner, repo), Method.GET);
client.UserAgent = UserAgent;
var response = client.Execute<List<GitHubContributorModel>>(request);
return response;
}
}
}
+23
View File
@@ -241,6 +241,18 @@
<HintPath>..\packages\semver.1.1.2\lib\net451\Semver.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Skybrud.Essentials, Version=1.0.8.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Skybrud.Essentials.1.0.8\lib\net45\Skybrud.Essentials.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Skybrud.Social.Core">
<HintPath>..\packages\Skybrud.Social.Core.1.0.0-beta9\lib\net45\Skybrud.Social.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Skybrud.Social.Meetup, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Skybrud.Social.Meetup.1.0.0-beta002\lib\net45\Skybrud.Social.Meetup.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLCE4Umbraco, Version=1.0.6261.14294, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\UmbracoCms.Core.7.5.10\lib\SQLCE4Umbraco.dll</HintPath>
<Private>True</Private>
@@ -391,7 +403,16 @@
</ItemGroup>
<ItemGroup>
<Compile Include="CamelCaseFormatter.cs" />
<Compile Include="Community\Controllers\GitHubContributorController.cs" />
<Compile Include="Community\Controllers\MeetupsController.cs" />
<Compile Include="Community\Controllers\GitHubGlobalContributorModel.cs" />
<Compile Include="Community\Controllers\TwitterSearchController.cs" />
<Compile Include="Community\Models\GitHubContributorModel.cs" />
<Compile Include="Community\Models\IGitHubContributorModel.cs" />
<Compile Include="Community\Models\MeetupEventsModel.cs" />
<Compile Include="Community\Models\MeetupItem.cs" />
<Compile Include="Community\Models\GitHubContributorsModel.cs" />
<Compile Include="Community\Models\IGitHubContributorsModel.cs" />
<Compile Include="Community\Models\TweetsModel.cs" />
<Compile Include="CustomDateTimeConvertor.cs" />
<Compile Include="Documentation\Busineslogic\ConventionExtensions.cs" />
@@ -401,6 +422,7 @@
<Compile Include="Documentation\Busineslogic\GithubSourcePull\ZipDownloader.cs" />
<Compile Include="Documentation\Busineslogic\MarkdownLogic.cs" />
<Compile Include="Documentation\Controllers\AppVeyorAuthorizeFilterAttribute.cs" />
<Compile Include="Documentation\Controllers\LessonsController.cs" />
<Compile Include="Documentation\Models\Artifact.cs" />
<Compile Include="Documentation\Models\Compilationmessage.cs" />
<Compile Include="Documentation\Models\DocFxUpdateModel.cs" />
@@ -504,6 +526,7 @@
<Compile Include="NotificationsWeb\Services\NotificationService.cs" />
<Compile Include="NotificationsWeb\Singleton.cs" />
<Compile Include="Our\Api\CommunityController.cs" />
<Compile Include="Our\Api\GitHubController.cs" />
<Compile Include="Our\Api\SearchController.cs" />
<Compile Include="Our\Api\YouTrackApiController.cs" />
<Compile Include="Our\Businesslogic\ProjectContributor.cs" />
@@ -60,6 +60,16 @@ namespace OurUmbraco.Repository.Controllers
var starterKits = new List<StarterKit>();
var allConfiguredVersions = UWikiFileVersion.GetAllVersions();
// for 7.6.4+ we change behavior and only provide one starter kit
if (version >= new System.Version(7, 6, 4))
{
officialStarterKitGuidCollection = new List<string>
{
ConfigurationManager.AppSettings["UmbracoStarterKitDefault"]
};
}
foreach (var umbracoNode in umbracoNodes)
{
// If it's not in the official list, move on to the next package
@@ -230,6 +230,8 @@ namespace OurUmbraco.Repository.Services
//get the strict packages in the correct desc order
var strictPackageFileVersions = GetAllStrictSupportedPackageVersions(allPackageFiles).ToArray();
//these are ordered by package version desc
var nonStrictPackageFiles = GetNonStrictSupportedPackageVersions(allPackageFiles).ToArray();
var packageDetails = new PackageDetails(package)
{
@@ -259,31 +261,7 @@ namespace OurUmbraco.Repository.Services
else if (currentUmbracoVersion < version75)
{
//if the umbraco version is < 7.5 it means that strict package formats are not supported
//TODO: Now we have to do the opposite of below and filter out any package file versions that have strict
// umbraco dependencies applied. Anything that has 7.5 (which would be the very minimum strict dependency) we can check for
//these are ordered by package version desc
var nonStrictPackageFiles = GetNonStrictSupportedPackageVersions(allPackageFiles).ToArray();
if (nonStrictPackageFiles.Length != 0)
{
//there might be a case where the 'current release file' is not the latest version found, so let's check if
//the latest release file is included in the non-strict packages and if so we'll use that, otherwise we'll use the latest
var found = nonStrictPackageFiles.FirstOrDefault(x => x.FileId == currentReleaseFile);
if (found != null)
{
//it's included in the non strict packages so use it
packageDetails.ZipUrl = string.Concat(BASE_URL, "/FileDownload?id=", currentReleaseFile);
packageDetails.ZipFileId = currentReleaseFile;
}
else
{
//use the latest available package version
packageDetails.ZipUrl = string.Concat(BASE_URL, "/FileDownload?id=", nonStrictPackageFiles[0].FileId);
packageDetails.ZipFileId = nonStrictPackageFiles[0].FileId;
}
}
AssignLatestNonStrictPackageFile(nonStrictPackageFiles, currentReleaseFile, packageDetails);
}
else
{
@@ -307,7 +285,15 @@ namespace OurUmbraco.Repository.Services
//got one! so use it's id for the file download
packageDetails.ZipUrl = string.Concat(BASE_URL, "/FileDownload?id=", found);
packageDetails.ZipFileId = found;
}
}
else if (nonStrictPackageFiles.Length > 0)
{
//Here's the other case, if this package has both strict and non-strict package file versions and we didn't find one above,
//than we need to determine if the latest non-strict package file format should be used for the current version being passed in
AssignLatestNonStrictPackageFile(nonStrictPackageFiles, currentReleaseFile, packageDetails);
}
}
packageDetails.Created = content.CreateDate;
@@ -315,6 +301,28 @@ namespace OurUmbraco.Repository.Services
return packageDetails;
}
private void AssignLatestNonStrictPackageFile(PackageVersionSupport[] nonStrictPackageFiles, int currentReleaseFile, PackageDetails packageDetails)
{
if (nonStrictPackageFiles.Length > 0)
{
//there might be a case where the 'current release file' is not the latest version found, so let's check if
//the latest release file is included in the non-strict packages and if so we'll use that, otherwise we'll use the latest
var found = nonStrictPackageFiles.FirstOrDefault(x => x.FileId == currentReleaseFile);
if (found != null)
{
//it's included in the non strict packages so use it
packageDetails.ZipUrl = string.Concat(BASE_URL, "/FileDownload?id=", currentReleaseFile);
packageDetails.ZipFileId = currentReleaseFile;
}
else
{
//use the latest available package version
packageDetails.ZipUrl = string.Concat(BASE_URL, "/FileDownload?id=", nonStrictPackageFiles[0].FileId);
packageDetails.ZipFileId = nonStrictPackageFiles[0].FileId;
}
}
}
private List<PackageCompatibility> GetPackageCompatibility(IPublishedContent content)
{
var service = new VersionCompatibilityService(DatabaseContext);
@@ -365,6 +373,8 @@ namespace OurUmbraco.Repository.Services
.Where(x => x.PackageVersion != null && x.MinUmbracoVersion != null)
.OrderByDescending(x => x.PackageVersion)
.ThenByDescending(x => x.MinUmbracoVersion)
//need to sort by latest file Id too since multiple files can target the same umbraco versions but we want to take the latest uploaded file
.ThenByDescending(x => x.FileId)
.ToArray();
return allVersions;
}
@@ -384,6 +394,8 @@ namespace OurUmbraco.Repository.Services
.Select(x => new PackageVersionSupport(x.Id, x.Version.Version.GetFromUmbracoString(reduceToConfigured:false), null))
.Where(x => x.PackageVersion != null)
.OrderByDescending(x => x.PackageVersion)
//need to sort by latest file Id too since multiple files can target the same umbraco versions but we want to take the latest uploaded file
.ThenByDescending(x => x.FileId)
.ToArray();
return allVersions;
}
+3 -2
View File
@@ -415,11 +415,12 @@ namespace OurUmbraco.Wiki.BusinessLogic
public static List<UmbracoVersion> GetVersionsFromString(string p)
{
var umbracoVersions = new List<UmbracoVersion>();
var availableVersions = UmbracoVersion.AvailableVersions();
foreach (var ver in p.Split(','))
{
if (UmbracoVersion.AvailableVersions().ContainsKey(ver))
umbracoVersions.Add(UmbracoVersion.AvailableVersions()[ver]);
if (availableVersions.ContainsKey(ver))
umbracoVersions.Add(availableVersions[ver]);
}
return umbracoVersions;
+3
View File
@@ -55,6 +55,9 @@
<package id="RestSharp" version="104.1" targetFramework="net451" />
<package id="semver" version="1.1.2" targetFramework="net452" />
<package id="SharpZipLib" version="0.86.0" targetFramework="net452" />
<package id="Skybrud.Essentials" version="1.0.8" targetFramework="net452" />
<package id="Skybrud.Social.Core" version="1.0.0-beta9" targetFramework="net452" />
<package id="Skybrud.Social.Meetup" version="1.0.0-beta002" targetFramework="net452" />
<package id="System.Collections" version="4.3.0" targetFramework="net452" />
<package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net452" />
<package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net452" />
+27 -14
View File
@@ -1,11 +1,16 @@
@ECHO OFF
SETLOCAL
:: SETLOCAL is on, so changes to the path not persist to the actual user's path
SET release=%1
SET toolsFolder=%CD%\tools\
ECHO Installing Npm NuGet Package
SET nuGetFolder=%CD%\..\packages\
ECHO Configured packages folder: %nuGetFolder%
ECHO Current folder: %CD%
%CD%\tools\nuget.exe install Npm.js -OutputDirectory %nuGetFolder% -Verbosity quiet
SET toolsFolder=%CD%\tools
SET nodeFileName=node-v4.5.0-win-x86.7z
SET nodeExtractFolder=%toolsFolder%node.js.450
IF NOT EXIST %nodeExtractFolder% (
@@ -16,10 +21,21 @@ IF NOT EXIST %nodeExtractFolder% (
)
FOR /f "delims=" %%A in ('dir %nodeExtractFolder%\node* /b') DO SET "nodePath=%nodeExtractFolder%\%%A"
FOR /f "delims=" %%A in ('dir %nuGetFolder%node.js.* /b') do set "nodePath=%nuGetFolder%%%A\"
FOR /f "delims=" %%A in ('dir %nuGetFolder%npm.js.* /b') do set "npmPath=%nuGetFolder%%%A\tools\"
ECHO Adding Npm and Node to path
REM SETLOCAL is on, so changes to the path not persist to the actual user's path
PATH=%npmPath%;%nodePath%;%PATH%
SET buildFolder=%CD%
ECHO Change directory to %CD%\..\OurUmbraco.Client\
CD %CD%\..\OurUmbraco.Client\
SET nuGetFolder=%CD%\..\packages\
FOR /f "delims=" %%A in ('dir %nuGetFolder%npm.js.* /b') DO SET "npmPath=%nuGetFolder%%%A\tools\"
IF [%npmPath%] == [] GOTO :installnpm
IF NOT [%npmPath%] == [] GOTO :build
:installnpm
ECHO Downloading npm
@@ -31,19 +47,16 @@ IF NOT [%npmPath%] == [] GOTO :build
GOTO :build
:build
ECHO Gulp build the client side files
PATH=%npmPath%;%nodePath%
SET buildFolder=%CD%
ECHO Change directory to %CD%\..\OurUmbraco.Client\
CD %CD%\..\OurUmbraco.Client\
ECHO Do npm install and the gulp build
SET npm="%nodePath%\node.exe" "%npmPath%node_modules\npm\bin\npm-cli.js" %*
%npm% cache clean
%npm% install
%npm% install --save-dev jshint gulp-jshint
%npm% install -g install gulp -g
gulp
gulp build
ECHO Move back to the build folder
CD %buildFolder%
GOTO :EOF
CD %buildFolder%
Binary file not shown.