Skip to content

Commit a0a814f

Browse files
committed
Merge branch 'rc-v3.4'
2 parents d7347ee + 741d562 commit a0a814f

Some content is hidden

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

64 files changed

+117419
-262
lines changed

.gitignore

+2-2
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ $RECYCLE.BIN/
156156
# =========================
157157

158158
# ignore all except example .config & project files files
159-
**/_ConfigSource/*.config
160-
!**/_ConfigSource/EXAMPLE-*.config
159+
**/_[Cc]onfigSource/*.config
160+
!**/_[Cc]onfigSource/EXAMPLE-*.config
161161
# Red-Gate SQL Data Compare project files
162162
*.sdc
163163
!EXAMPLE-*.sdc

ClassSchedule.Web/ClassSchedule.Web.csproj

+29-15
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Test|AnyCPU' ">
3333
<DebugSymbols>true</DebugSymbols>
3434
<OutputPath>bin\</OutputPath>
35-
<DefineConstants>TRACE;DEBUG;ENABLE_PROFILING</DefineConstants>
35+
<DefineConstants>TRACE;DEBUG</DefineConstants>
3636
<DebugType>full</DebugType>
3737
<PlatformTarget>AnyCPU</PlatformTarget>
3838
<ErrorReport>prompt</ErrorReport>
@@ -58,6 +58,9 @@
5858
<Reference Include="Common.Logging.Elmah">
5959
<HintPath>..\packages\Common.Logging.Elmah.1.2.1\lib\net40\Common.Logging.Elmah.dll</HintPath>
6060
</Reference>
61+
<Reference Include="Common.Logging.NLog20">
62+
<HintPath>..\packages\Common.Logging.NLog20.2.1.2\lib\net40\Common.Logging.NLog20.dll</HintPath>
63+
</Reference>
6164
<Reference Include="CtcApi, Version=0.9.15.0, Culture=neutral, processorArchitecture=MSIL">
6265
<SpecificVersion>False</SpecificVersion>
6366
<HintPath>..\packages\CtcApi.0.9.15.0\lib\net40\CtcApi.dll</HintPath>
@@ -72,8 +75,9 @@
7275
<Reference Include="Elmah">
7376
<HintPath>..\packages\elmah.corelibrary.1.2.2\lib\Elmah.dll</HintPath>
7477
</Reference>
75-
<Reference Include="Elmah.Mvc">
76-
<HintPath>..\packages\Elmah.MVC.2.0.2\lib\net40\Elmah.Mvc.dll</HintPath>
78+
<Reference Include="Elmah.Mvc, Version=2.0.0.29988, Culture=neutral, processorArchitecture=MSIL">
79+
<SpecificVersion>False</SpecificVersion>
80+
<HintPath>..\packages\Elmah.MVC.2.1.1\lib\net40\Elmah.Mvc.dll</HintPath>
7781
</Reference>
7882
<Reference Include="EntityFramework">
7983
<HintPath>..\packages\EntityFramework.4.1.10715.0\lib\EntityFramework.dll</HintPath>
@@ -89,6 +93,9 @@
8993
<Reference Include="MvcMiniProfiler">
9094
<HintPath>..\packages\MiniProfiler.1.9\lib\net40\MvcMiniProfiler.dll</HintPath>
9195
</Reference>
96+
<Reference Include="NLog">
97+
<HintPath>..\packages\NLog.2.1.0\lib\net40\NLog.dll</HintPath>
98+
</Reference>
9299
<Reference Include="System.Data.Entity" />
93100
<Reference Include="System.DirectoryServices" />
94101
<Reference Include="System.DirectoryServices.AccountManagement" />
@@ -189,6 +196,7 @@
189196
<Compile Include="Models\SectionEditModelBinder.cs" />
190197
<Compile Include="Models\SectionIdModelBinder.cs" />
191198
<Compile Include="Models\SectionWithSeats.cs" />
199+
<Compile Include="Models\SubjectModel.cs" />
192200
<Compile Include="Models\SubjectViewModel.cs" />
193201
<Compile Include="Models\YearQuarterModel.cs" />
194202
<Compile Include="Models\YearQuarterSubjectModel.cs" />
@@ -379,6 +387,7 @@
379387
<Content Include="Views\_ViewStart.cshtml" />
380388
<Content Include="Views\Shared\Error.cshtml" />
381389
<Content Include="Views\Shared\_Layout.cshtml" />
390+
<Content Include="_configSource\Smtp.config" />
382391
</ItemGroup>
383392
<ItemGroup>
384393
<Folder Include="globals\btheme_v0.1\dotNET\" />
@@ -411,18 +420,23 @@
411420
<DependentUpon>web.config</DependentUpon>
412421
</Content>
413422
<Content Include="Views\Shared\CourseDescriptions.cshtml" />
414-
<None Include="_ConfigSource\RoleManager.config" />
415-
<None Include="_ConfigSource\CasClient.config" />
416-
<None Include="_ConfigSource\ElmahAuthorization.config" />
417-
<None Include="_ConfigSource\Authentication.config" />
418-
<None Include="_ConfigSource\AppSettings.config" />
419-
<None Include="_ConfigSource\ConnectionStrings.config" />
420-
<None Include="_ConfigSource\EXAMPLE-AppSettings.config" />
421-
<None Include="_ConfigSource\EXAMPLE-Authentication.config" />
422-
<None Include="_ConfigSource\EXAMPLE-CasClient.config" />
423-
<None Include="_ConfigSource\EXAMPLE-ConnectionStrings.config" />
424-
<None Include="_ConfigSource\EXAMPLE-ElmahAuthorization.config" />
425-
<None Include="_ConfigSource\EXAMPLE-RoleManager.config" />
423+
<Content Include="_configSource\ElmahMail.config" />
424+
<Content Include="_configSource\EXAMPLE-ElmahMail.config" />
425+
<Content Include="_configSource\EXAMPLE-NLog.config" />
426+
<Content Include="_configSource\EXAMPLE-Smtp.config" />
427+
<Content Include="_configSource\NLog.config" />
428+
<None Include="_configSource\RoleManager.config" />
429+
<None Include="_configSource\CasClient.config" />
430+
<None Include="_configSource\ElmahAuthorization.config" />
431+
<None Include="_configSource\Authentication.config" />
432+
<None Include="_configSource\AppSettings.config" />
433+
<None Include="_configSource\ConnectionStrings.config" />
434+
<None Include="_configSource\EXAMPLE-AppSettings.config" />
435+
<None Include="_configSource\EXAMPLE-Authentication.config" />
436+
<None Include="_configSource\EXAMPLE-CasClient.config" />
437+
<None Include="_configSource\EXAMPLE-ConnectionStrings.config" />
438+
<None Include="_configSource\EXAMPLE-ElmahAuthorization.config" />
439+
<None Include="_configSource\EXAMPLE-RoleManager.config" />
426440
</ItemGroup>
427441
<ItemGroup>
428442
<Content Include="Views\Classes\YearQuarter.cshtml" />

ClassSchedule.Web/Common/Helpers.cs

+112-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
using System.Linq;
99
using System.Text.RegularExpressions;
1010
using System.Web;
11+
using System.Web.Routing;
1112
using CTCClassSchedule.Properties;
13+
using Common.Logging;
1214
using Ctc.Ods;
1315
using Ctc.Ods.Data;
1416
using Ctc.Ods.Types;
@@ -18,12 +20,15 @@
1820
using System.Configuration;
1921
using System.Text;
2022
using Ctc.Ods.Config;
23+
using Encoder = Microsoft.Security.Application.Encoder;
2124

2225
namespace CTCClassSchedule.Common
2326
{
2427
public static class Helpers
2528
{
26-
/// <summary>
29+
private static readonly ILog _log = LogManager.GetCurrentClassLogger();
30+
31+
/// <summary>
2732
/// Useful if a helper method works with a timespan and should default to
2833
/// either 12:00am or 23:59pm (start time/end time).
2934
/// </summary>
@@ -266,7 +271,7 @@ public static CourseID getCourseIdFromString(string courseId)
266271
ApiSettings _apiSettings = ConfigurationManager.GetSection(ApiSettings.SectionName) as ApiSettings;
267272
string commonCourseChar = _apiSettings.RegexPatterns.CommonCourseChar;
268273

269-
return new CourseID(subject.Replace(commonCourseChar, string.Empty), courseNumber, subject.Contains(commonCourseChar));
274+
return new CourseID(subject.Replace(commonCourseChar, String.Empty), courseNumber, subject.Contains(commonCourseChar));
270275
}
271276

272277
/// <summary>
@@ -430,7 +435,7 @@ static public IDictionary<string, object> getLinkParams(HttpRequestBase httpRequ
430435
{
431436
string value = httpRequest.QueryString.AllKeys.Contains(key) ? httpRequest.QueryString[key] : httpRequest.Form[key];
432437

433-
if (!string.IsNullOrWhiteSpace(value))
438+
if (!String.IsNullOrWhiteSpace(value))
434439
{
435440
if (linkParams.ContainsKey(key))
436441
{
@@ -663,7 +668,7 @@ public static IList<SectionsBlock> GroupSectionsIntoBlocks(IList<SectionWithSeat
663668
IList<SectionWithSeats> remainingSections = nonLinkedSections.Skip(processedCount).ToList();
664669
SectionWithSeats firstSection = remainingSections.First();
665670
// TODO: Replace BuildCourseID() with this logic - and pull in CommonCourceChar from .config
666-
string blockCourseID = string.Format("{0}{1} {2}", firstSection.CourseSubject, firstSection.IsCommonCourse ? "&" : string.Empty, firstSection.CourseNumber);
671+
string blockCourseID = String.Format("{0}{1} {2}", firstSection.CourseSubject, firstSection.IsCommonCourse ? "&" : String.Empty, firstSection.CourseNumber);
667672

668673
if (allLinkedSections.Any(l => l.LinkedTo == firstSection.ID.ItemNumber))
669674
{
@@ -933,6 +938,11 @@ static private string getYRQValueForBookstoreURL(YearQuarter yrq)
933938
return String.Concat(quarter, year);
934939
}
935940

941+
/// <summary>
942+
///
943+
/// </summary>
944+
/// <param name="linkedSections"></param>
945+
/// <returns></returns>
936946
public static IList<SectionWithSeats> ParseCommonHeadingLinkedSections(List<SectionWithSeats> linkedSections)
937947
{
938948
string prevCourseID = String.Empty;
@@ -957,5 +967,103 @@ public static IList<SectionWithSeats> ParseCommonHeadingLinkedSections(List<Sect
957967

958968
return common;
959969
}
970+
971+
// TODO: Move StripHtml() into CtcApi
972+
/// <summary>
973+
///
974+
/// </summary>
975+
/// <param name="withHtml"></param>
976+
/// <param name="whitelistPattern"></param>
977+
/// <returns></returns>
978+
public static string StripHtml(string withHtml, string whitelistPattern = null)
979+
{
980+
string stripped;
981+
if (String.IsNullOrWhiteSpace(whitelistPattern))
982+
{
983+
whitelistPattern = ConfigurationManager.AppSettings["CMSHtmlParsingAllowedElements"];
984+
}
985+
try
986+
{
987+
string pattern = @"</?(?(?=" + whitelistPattern +
988+
@")notag|[a-zA-Z0-9]+)(?:\s[a-zA-Z0-9\-]+=?(?:(["",']?).*?\1?)?)*\s*/?>";
989+
stripped = Regex.Replace(withHtml, pattern, String.Empty);
990+
}
991+
catch (Exception ex)
992+
{
993+
stripped = Encoder.HtmlEncode(withHtml);
994+
_log.Warn(m => m("Unable to remove HTML from string '{0}'\nReturning HTML-encoded string instead.\n{1}", withHtml, ex));
995+
}
996+
return stripped;
997+
}
998+
999+
/// <summary>
1000+
/// Gets the course outcome information by scraping the Bellevue College
1001+
/// course outcomes website
1002+
/// </summary>
1003+
public static dynamic GetCourseOutcome(ICourseID courseId)
1004+
{
1005+
string fullCourseID = BuildCourseID(courseId.Number, courseId.Subject.TrimEnd(), courseId.IsCommonCourse);
1006+
string courseOutcomes;
1007+
try
1008+
{
1009+
Service1Client client = new Service1Client();
1010+
string rawCourseOutcomes = client.GetCourseOutcome(fullCourseID);
1011+
if (rawCourseOutcomes.IndexOf("<li>", StringComparison.OrdinalIgnoreCase) >= 0)
1012+
{
1013+
courseOutcomes = StripHtml(rawCourseOutcomes, "ul|UL|li|LI");
1014+
}
1015+
else
1016+
{
1017+
courseOutcomes = StripHtml(rawCourseOutcomes, "");
1018+
string[] outcomeArray = courseOutcomes.Split('\n');
1019+
1020+
StringBuilder outcomes = new StringBuilder("<ul>");
1021+
foreach (string outcome in outcomeArray)
1022+
{
1023+
outcomes.AppendFormat("<li>{0}</li>", outcome);
1024+
}
1025+
outcomes.Append("</ul>");
1026+
1027+
courseOutcomes = outcomes.ToString();
1028+
}
1029+
}
1030+
catch (Exception ex)
1031+
{
1032+
// TODO: log exception details
1033+
courseOutcomes = "Error: Cannot find course outcome for this course or cannot connect to the course outcomes webservice.";
1034+
_log.Warn(m => m("Unable to retrieve course outomes for '{0}'", fullCourseID), ex);
1035+
}
1036+
1037+
return courseOutcomes;
1038+
}
1039+
1040+
/// <summary>
1041+
/// Allows user to enter "current" in URL in place of quarter
1042+
/// </summary>
1043+
/// <param name="quarter"></param>
1044+
/// <param name="currentQuarter"></param>
1045+
/// <param name="routeData"></param>
1046+
/// <returns></returns>
1047+
public static YearQuarter DetermineRegistrationQuarter(string quarter, YearQuarter currentQuarter, RouteData routeData)
1048+
{
1049+
YearQuarter yrq;
1050+
if (String.IsNullOrWhiteSpace(quarter))
1051+
{
1052+
yrq = null;
1053+
}
1054+
else
1055+
{
1056+
if (quarter.ToUpper() == "CURRENT")
1057+
{
1058+
yrq = currentQuarter;
1059+
routeData.Values["YearQuarter"] = yrq.FriendlyName.Replace(" ", string.Empty);
1060+
}
1061+
else
1062+
{
1063+
yrq = YearQuarter.FromFriendlyName(quarter);
1064+
}
1065+
}
1066+
return yrq;
1067+
}
9601068
}
9611069
}

ClassSchedule.Web/Controllers/ApiController.cs

+1-26
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ public ActionResult ClassEdit(FormCollection collection)
367367
string username = HttpContext.User.Identity.Name;
368368
string footnote = collection["Footnote"];
369369

370-
footnote = StripHtml(footnote);
370+
footnote = Helpers.StripHtml(footnote);
371371

372372
if (ModelState.IsValid)
373373
{
@@ -476,31 +476,6 @@ where apiSubjects.Contains(s.CoursePrefixID.TrimEnd('&'))
476476
#endregion
477477

478478
#region Private methods
479-
/// <summary>
480-
///
481-
/// </summary>
482-
/// <param name="withHtml"></param>
483-
/// <returns></returns>
484-
private string StripHtml(string withHtml)
485-
{
486-
string stripped;
487-
// BUG: The appSetting value "CMSHtmlParsingAllowedElements" is not present
488-
string whitelist = ConfigurationManager.AppSettings["CMSHtmlParsingAllowedElements"];
489-
490-
try
491-
{
492-
string pattern = @"</?(?(?=" + whitelist +
493-
@")notag|[a-zA-Z0-9]+)(?:\s[a-zA-Z0-9\-]+=?(?:(["",']?).*?\1?)?)*\s*/?>";
494-
stripped = Regex.Replace(withHtml, pattern, string.Empty);
495-
}
496-
catch (Exception ex)
497-
{
498-
stripped = Microsoft.Security.Application.Encoder.HtmlEncode(withHtml);
499-
_log.Warn(
500-
m => m("Unable to remove HTML from string '{0}'\nReturning HTML-encoded string instead.\n{1}", withHtml, ex));
501-
}
502-
return stripped;
503-
}
504479
#endregion
505480
}
506481
}

0 commit comments

Comments
 (0)