├── .gitignore ├── .nuget ├── NuGet.Config ├── NuGet.exe └── NuGet.targets ├── Code ├── RavenOverflow.Core │ ├── Entities │ │ ├── Answer.cs │ │ ├── Comment.cs │ │ ├── Extensions.cs │ │ ├── OAuthData.cs │ │ ├── OAuthProvider.cs │ │ ├── Question.cs │ │ ├── RootAggregate.cs │ │ ├── User.cs │ │ └── Vote.cs │ ├── Extensions │ │ └── CommonExtensions.cs │ ├── Filters │ │ ├── QuestionFilters.cs │ │ └── UserFilters.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── RavenOverflow.Core.csproj │ ├── Services │ │ ├── IQuestionService.cs │ │ └── IUserService.cs │ └── packages.config ├── RavenOverflow.FakeData │ ├── FakeQuestions.cs │ ├── FakeUsers.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── RavenOverflow.FakeData.csproj │ └── packages.config ├── RavenOverflow.Services │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── QuestionService.cs │ ├── RavenDbBaseService.cs │ ├── RavenOverflow.Services.csproj │ ├── UserService.cs │ └── packages.config ├── RavenOverflow.Tests │ ├── ControllerUtilities.cs │ ├── Controllers │ │ ├── ControllerUtilities.cs │ │ ├── HomeControllerFacts.cs │ │ ├── QuestionControllerFacts.cs │ │ └── UserControllerFacts.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── RavenOverflow.Tests.csproj │ ├── Services │ │ └── QuestionServiceFacts.cs │ └── packages.config └── RavenOverflow.Web │ ├── App_Start │ ├── MagicalUnicornCustomErrorHandling.cs │ └── StructuremapMvc.cs │ ├── Areas │ └── Question │ │ ├── Controllers │ │ └── QuestionsController.cs │ │ ├── Models │ │ ├── QuestionInputModel.cs │ │ └── QuestionViewModel.cs │ │ ├── QuestionAreaRegistration.cs │ │ └── Views │ │ ├── Questions │ │ └── Create.cshtml │ │ └── Web.config │ ├── AutoMapper │ ├── AutoMapperBootstrapper.cs │ └── TagsResolver.cs │ ├── Content │ ├── Images │ │ └── Error │ │ │ ├── NotFound.jpg │ │ │ └── ServerError.jpg │ ├── LeahCulverAvatar.png │ ├── Site.css │ └── logo-ravendb.png │ ├── Controllers │ ├── BaseController.cs │ ├── ErrorController.cs │ └── HomeController.cs │ ├── DependencyResolution │ ├── AuthenticationRegistry.cs │ ├── IoC.cs │ ├── RavenDbRegistry.cs │ ├── ServiceRegistry.cs │ └── StructureMapDependencyResolver.cs │ ├── Global.asax │ ├── Global.asax.cs │ ├── Models │ ├── ClaimsUser.cs │ ├── HtmlExtensions.cs │ ├── ViewModels │ │ ├── AuthenticationViewModel.cs │ │ ├── IndexViewModel.cs │ │ ├── QuestionListViewModel.cs │ │ ├── QuestionWithDisplayName.cs │ │ ├── TagListViewModel.cs │ │ └── UserTagListViewModel.cs │ ├── _LayoutViewModel.cs │ └── _MainNavigationViewModel.cs │ ├── Properties │ └── AssemblyInfo.cs │ ├── RavenDb │ ├── DocumentStoreExtensions.cs │ ├── HelperUtilities.cs │ └── Indexes │ │ ├── Questions_Search.cs │ │ ├── RavenFacetTags.cs │ │ ├── RecentPopularTags.cs │ │ └── RecentPopularTagsMapOnly.cs │ ├── RavenOverflow.Web.csproj │ ├── Views │ ├── Error │ │ ├── NotFound.cshtml │ │ └── ServerError.cshtml │ ├── Home │ │ └── Index.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ ├── _Authentication.cshtml │ │ ├── _ErrorLayout.cshtml │ │ ├── _Layout.cshtml │ │ ├── _MainNavigation.cshtml │ │ ├── _QuestionList.cshtml │ │ ├── _QuestionTagList.cshtml │ │ ├── _TagList.cshtml │ │ ├── _TagListVertical.cshtml │ │ ├── _TagSearch.cshtml │ │ └── _UserTagList.cshtml │ ├── Web.config │ └── _ViewStart.cshtml │ ├── Web.Debug.config │ ├── Web.Release.config │ ├── Web.config │ └── packages.config ├── README.markdown ├── RavenOverflow.sln └── RavenOverflow.sln.DotSettings /.gitignore: -------------------------------------------------------------------------------- 1 | *.obj 2 | *.pdb 3 | *.user 4 | *.aps 5 | *.pch 6 | *.vspscc 7 | *.vssscc 8 | *_i.c 9 | *_p.c 10 | *.ncb 11 | *.suo 12 | *.tlb 13 | *.tlh 14 | *.bak 15 | *.cache 16 | *.ilk 17 | *.log 18 | *.lib 19 | *.sbr 20 | *.scc 21 | [Bb]in 22 | [Dd]ebug*/ 23 | obj/ 24 | [Rr]elease*/ 25 | _ReSharper*/ 26 | *.[Pp]ublish.xml 27 | *.resharper* 28 | AppData/ 29 | App_Data/ 30 | *.log.* 31 | [Ll]ogs/ 32 | [Dd]ata/ 33 | [Pp]ackages/ 34 | [Tt]humbs.db 35 | [Tt]est[Rr]esult* 36 | [Bb]uild[Ll]og.* 37 | *.sln.DotSettings.* 38 | -------------------------------------------------------------------------------- /.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureKrome/RavenOverflow/2e91b036b0da1f30cfaf27aab5c98dfed5ce3b39/.nuget/NuGet.exe -------------------------------------------------------------------------------- /.nuget/NuGet.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildProjectDirectory)\..\ 5 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) 6 | $(NuGetToolsPath)\nuget.exe 7 | $([System.IO.Path]::Combine($(ProjectDir), "packages.config")) 8 | $([System.IO.Path]::Combine($(SolutionDir), "packages")) 9 | $(TargetDir.Trim('\\')) 10 | 11 | 12 | "" 13 | 14 | 15 | false 16 | 17 | 18 | false 19 | 20 | 21 | "$(NuGetExePath)" install "$(PackagesConfig)" -source $(PackageSources) -o "$(PackagesDir)" 22 | "$(NuGetExePath)" pack "$(ProjectPath)" -p Configuration=$(Configuration) -o "$(PackageOutputDir)" -symbols 23 | 24 | 25 | 26 | RestorePackages; 27 | $(BuildDependsOn); 28 | 29 | 30 | 31 | 32 | $(BuildDependsOn); 33 | BuildPackage; 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 46 | 47 | 48 | 49 | 51 | 52 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Core/Entities/Answer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace RavenOverflow.Core.Entities 5 | { 6 | public class Answer 7 | { 8 | public string CreatedByUserId { get; set; } 9 | public string Content { get; set; } 10 | public DateTime CreatedOn { get; set; } 11 | public string LastEditedByUserId { get; set; } 12 | public DateTime? LastEditedOn { get; set; } 13 | public Vote Vote { get; set; } 14 | public ICollection Comments { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Core/Entities/Comment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace RavenOverflow.Core.Entities 4 | { 5 | public class Comment 6 | { 7 | public string Content { get; set; } 8 | public DateTime CreatedOn { get; set; } // This should always be Utc. 9 | public string CreatedByUserId { get; set; } 10 | public int UpVoteCount { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Core/Entities/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Security.Cryptography; 4 | 5 | namespace RavenOverflow.Core.Entities 6 | { 7 | public static class Extensions 8 | { 9 | public static IList ToRandomList(this IList source, int numberOfItems) 10 | { 11 | if (numberOfItems <= 0) 12 | { 13 | throw new ArgumentOutOfRangeException("numberOfItems"); 14 | } 15 | 16 | IList results = new List(); 17 | 18 | RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); 19 | byte[] rndBytes = new byte[4]; 20 | rng.GetBytes(rndBytes); 21 | int randomNumber = BitConverter.ToInt32(rndBytes, 0); 22 | 23 | 24 | // Based upon: http://stackoverflow.com/questions/48087/select-a-random-n-elements-from-listt-in-c 25 | var rand = new Random(randomNumber); 26 | double needed = numberOfItems; 27 | int available = source.Count; 28 | 29 | while (results.Count < numberOfItems) 30 | { 31 | if (rand.NextDouble() < needed/available) 32 | { 33 | results.Add(source[available - 1]); 34 | needed--; 35 | } 36 | available--; 37 | } 38 | 39 | return results; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Core/Entities/OAuthData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace RavenOverflow.Core.Entities 4 | { 5 | public class OAuthData 6 | { 7 | public string Id { get; set; } 8 | public OAuthProvider OAuthProvider { get; set; } 9 | public string AccessToken { get; set; } 10 | public DateTime ExpiresOn { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Core/Entities/OAuthProvider.cs: -------------------------------------------------------------------------------- 1 | namespace RavenOverflow.Core.Entities 2 | { 3 | public enum OAuthProvider 4 | { 5 | Unknown, 6 | Facebook, 7 | Twitter 8 | } 9 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Core/Entities/Question.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace RavenOverflow.Core.Entities 6 | { 7 | public class Question : RootAggregate 8 | { 9 | public Question() 10 | { 11 | NumberOfViews = 1; 12 | CreatedOn = DateTime.UtcNow; 13 | } 14 | 15 | [Required] 16 | public string Subject { get; set; } 17 | [Required] 18 | public string Content { get; set; } 19 | public DateTime CreatedOn { get; set; } // This should always be Utc. 20 | [Required] 21 | public ICollection Tags { get; set; } 22 | [Required(ErrorMessage = "You need to be logged in to ask a question.")] 23 | public string CreatedByUserId { get; set; } 24 | public ICollection Answers { get; set; } 25 | public int NumberOfViews { get; set; } 26 | public Vote Vote { get; set; } 27 | public ICollection Comments { get; set; } 28 | } 29 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Core/Entities/RootAggregate.cs: -------------------------------------------------------------------------------- 1 | namespace RavenOverflow.Core.Entities 2 | { 3 | public abstract class RootAggregate 4 | { 5 | public string Id { get; set; } 6 | 7 | //[JsonIgnore] 8 | //public int IdAsANumber 9 | //{ 10 | // get 11 | // { 12 | // if (string.IsNullOrEmpty(Id)) 13 | // { 14 | // return 0; 15 | // } 16 | 17 | // int index = Id.IndexOf('/'); 18 | // if (index < 0) 19 | // { 20 | // return 0; 21 | // } 22 | 23 | // int id; 24 | // return int.TryParse(Id.Substring(index + 1, Id.Length - index - 1), out id) ? id : 0; 25 | // } 26 | //} 27 | } 28 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Core/Entities/User.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace RavenOverflow.Core.Entities 5 | { 6 | public class User : RootAggregate 7 | { 8 | public string DisplayName { get; set; } 9 | public string Email { get; set; } 10 | public string FullName { get; set; } 11 | public DateTime CreatedOn { get; set; } 12 | public int Score { get; set; } 13 | public IList OAuthData { get; set; } 14 | public IList FavoriteTags { get; set; } 15 | public bool IsActive { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Core/Entities/Vote.cs: -------------------------------------------------------------------------------- 1 | namespace RavenOverflow.Core.Entities 2 | { 3 | public class Vote 4 | { 5 | public int UpVoteCount { get; set; } 6 | public int DownVoteCount { get; set; } 7 | public int FavoriteCount { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Core/Extensions/CommonExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace RavenOverflow.Core.Extensions 4 | { 5 | public static class CommonExtensions 6 | { 7 | public static DateTime ToUtcToday(this DateTime dateTime) 8 | { 9 | return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Core/Filters/QuestionFilters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using RavenOverflow.Core.Entities; 4 | 5 | namespace RavenOverflow.Core.Filters 6 | { 7 | public static class QuestionFilters 8 | { 9 | public static IQueryable OrderByCreatedByDescending(this IQueryable query) 10 | { 11 | return query.OrderByDescending(x => x.CreatedOn); 12 | } 13 | 14 | public static IQueryable WithAnyTag(this IQueryable query, string tag) 15 | { 16 | if (string.IsNullOrEmpty(tag)) 17 | { 18 | throw new ArgumentNullException("tag"); 19 | } 20 | 21 | return query.Where(x => x.Tags.Any(y => y == tag)); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Core/Filters/UserFilters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using RavenOverflow.Core.Entities; 4 | 5 | namespace RavenOverflow.Core.Filters 6 | { 7 | public static class UserFilters 8 | { 9 | public static IQueryable WithDisplayName(this IQueryable query, string displayName) 10 | { 11 | if(string.IsNullOrEmpty(displayName)) 12 | { 13 | throw new ArgumentNullException("displayName"); 14 | } 15 | 16 | return query.Where(x => x.DisplayName == displayName); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Core/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("RavenOverflow.Core")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("RavenOverflow.Core")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2011")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("c025a3bc-d29e-4d0f-b3b0-18d6874a3e70")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Core/RavenOverflow.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {58D8E77E-68D3-4623-A558-84B731E7725F} 9 | Library 10 | Properties 11 | RavenOverflow.Core 12 | RavenOverflow.Core 13 | v4.5 14 | 512 15 | ..\..\..\RavenOverflow\ 16 | true 17 | 18 | 19 | 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | false 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | false 37 | 38 | 39 | 40 | False 41 | ..\..\packages\RavenDB.Client.2.0.2330\lib\net40\Raven.Abstractions.dll 42 | 43 | 44 | False 45 | ..\..\packages\RavenDB.Client.2.0.2330\lib\net40\Raven.Client.Lightweight.dll 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 80 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Core/Services/IQuestionService.cs: -------------------------------------------------------------------------------- 1 | using RavenOverflow.Core.Entities; 2 | 3 | namespace RavenOverflow.Core.Services 4 | { 5 | public interface IQuestionService 6 | { 7 | Question Store(Question question); 8 | } 9 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Core/Services/IUserService.cs: -------------------------------------------------------------------------------- 1 | using RavenOverflow.Core.Entities; 2 | 3 | namespace RavenOverflow.Core.Services 4 | { 5 | public interface IUserService 6 | { 7 | User CreateOrUpdate(OAuthData oAuthData, string userName, string fullName, string email); 8 | } 9 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Core/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Code/RavenOverflow.FakeData/FakeQuestions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using CuttingEdge.Conditions; 5 | using FizzWare.NBuilder; 6 | using FizzWare.NBuilder.Generators; 7 | using RavenOverflow.Core.Entities; 8 | 9 | namespace RavenOverflow.FakeData 10 | { 11 | public static class FakeQuestions 12 | { 13 | private static readonly IList FakeTags = new List 14 | { 15 | "ravendb", 16 | "asp.net-mvc", 17 | "c#", 18 | "linq", 19 | "moq", 20 | ".net", 21 | ".net3.5", 22 | "elmah", 23 | "yui-compressor", 24 | "minify", 25 | "mono", 26 | "asp.net-mvc3", 27 | "ruby-on-rails", 28 | "elmah", 29 | "rubygems", 30 | "pew-pew" 31 | }; 32 | 33 | public static ICollection CreateFakeQuestions(IList userIds = null, 34 | int numberOfFakeQuestions = 50) 35 | { 36 | Condition.Requires(numberOfFakeQuestions).IsGreaterOrEqual(5); // First 5 questions are fixed. 37 | 38 | // If we don't have any fake userId's, then just create some fake users now. 39 | // Basically, we don't care what these values are. 40 | if (userIds == null) 41 | { 42 | userIds = FakeUsers.CreateFakeUsers(50).Select(x => x.Id).ToList(); 43 | } 44 | 45 | var fakeQuestions = new List(); 46 | 47 | IList fixedQuestion = CreateFixedFakeQuestions(userIds); 48 | Condition.Requires(numberOfFakeQuestions).IsNotLessThan(fixedQuestion.Count); 49 | 50 | fakeQuestions.AddRange(fixedQuestion); 51 | for (int i = 0; i < numberOfFakeQuestions - fixedQuestion.Count; i++) 52 | { 53 | fakeQuestions.Add(CreateAFakeQuestion(userIds.ToRandomList(1).Single(), userIds)); 54 | } 55 | 56 | return fakeQuestions; 57 | } 58 | 59 | public static Question CreateAFakeQuestion(string userId, IList answerUserIds) 60 | { 61 | Question fakeQuestion = Builder 62 | .CreateNew() 63 | .With(x => x.Id = null) 64 | .With(x => x.Subject = GetRandom.Phrase(GetRandom.Int(10, 50))) 65 | .With(x => x.Content = GetRandom.Phrase(GetRandom.Int(30, 500))) 66 | .And(x => x.CreatedByUserId = userId) 67 | .And(x => x.CreatedOn = GetRandom.DateTime(DateTime.UtcNow.AddMonths(-1), 68 | DateTime.UtcNow.AddMinutes(-5))) 69 | .And(x => x.NumberOfViews = GetRandom.PositiveInt(10000)) 70 | .And(x => x.Tags = FakeTags.ToRandomList(GetRandom.Int(1, 5))) 71 | .And(x => x.Vote = CreateAFakeVote()) 72 | .Build(); 73 | 74 | if (answerUserIds != null) 75 | { 76 | for (int i = 0; i < (GetRandom.Int(1, 20) <= 10 ? GetRandom.PositiveInt(6) : 0); i++) 77 | { 78 | if (fakeQuestion.Answers == null) 79 | { 80 | fakeQuestion.Answers = new List(); 81 | } 82 | 83 | fakeQuestion.Answers.Add(CreateAFakeAnswer(fakeQuestion.CreatedOn, 84 | answerUserIds.ToRandomList(1).Single())); 85 | } 86 | } 87 | 88 | return fakeQuestion; 89 | } 90 | 91 | private static Answer CreateAFakeAnswer(DateTime questionCreatedOn, string userId) 92 | { 93 | Answer answer = Builder 94 | .CreateNew() 95 | .With(x => x.Content = GetRandom.Phrase(GetRandom.Int(20, 100))) 96 | .And(x => x.CreatedOn = GetRandom.DateTime(questionCreatedOn.AddMinutes(5), DateTime.UtcNow)) 97 | .And(x => x.CreatedByUserId = userId) 98 | .And(x => x.Vote = CreateAFakeVote()) 99 | .Build(); 100 | 101 | for (int i = 0; i < (GetRandom.PositiveInt(20) <= 10 ? GetRandom.PositiveInt(6) : 0); i++) 102 | { 103 | if (answer.Comments == null) 104 | { 105 | answer.Comments = new List(); 106 | } 107 | answer.Comments.Add(CreateAFakeComment(questionCreatedOn)); 108 | } 109 | 110 | return answer; 111 | } 112 | 113 | private static Comment CreateAFakeComment(DateTime questionCreatedOn) 114 | { 115 | return Builder 116 | .CreateNew() 117 | .With(x => x.Content = GetRandom.Phrase(GetRandom.PositiveInt(20))) 118 | .And(x => x.CreatedOn = GetRandom.DateTime(questionCreatedOn.AddMinutes(5), DateTime.UtcNow)) 119 | .And(x => x.CreatedByUserId = string.Format("{0}.{1}", GetRandom.FirstName(), GetRandom.LastName())) 120 | // If Rand number between 1-10 <= 5, then votes = another rand numb between 1-5. else 0. 121 | .And(x => x.UpVoteCount = (GetRandom.PositiveInt(10) <= 6 ? GetRandom.PositiveInt(5) : 0)) 122 | .Build(); 123 | } 124 | 125 | private static Vote CreateAFakeVote() 126 | { 127 | return GetRandom.PositiveInt(5) == 1 128 | ? null 129 | : Builder 130 | .CreateNew() 131 | .With(y => y.UpVoteCount = GetRandom.PositiveInt(20)) 132 | .And(y => y.DownVoteCount = GetRandom.PositiveInt(3)) 133 | .And(y => y.FavoriteCount = GetRandom.PositiveInt(10)) 134 | .Build(); 135 | } 136 | 137 | private static IList CreateFixedFakeQuestions(IList userIds) 138 | { 139 | Condition.Requires(userIds).IsNotNull().IsLongerOrEqual(1); 140 | 141 | return new List 142 | { 143 | new Question 144 | { 145 | Subject = "How to query nested information in RavenDB?", 146 | Content = 147 | "I have the following document called Reservation: { \"CustomerId\": 1, \"Items\": [ { \"EmployeeId\": \"employees/1\", \"StartTime\": ...", 148 | CreatedOn = DateTime.UtcNow.AddMinutes(5), 149 | Tags = new List {"ravendb", ".net", "c#"}, 150 | CreatedByUserId = userIds.ToRandomList(1).Single(), 151 | NumberOfViews = 50, 152 | Vote = new Vote {DownVoteCount = 5, UpVoteCount = 10, FavoriteCount = 6}, 153 | Comments = new List 154 | { 155 | new Comment 156 | { 157 | Content = "Some comment 1", 158 | CreatedByUserId = 159 | userIds.ToRandomList(1).Single(), 160 | CreatedOn = DateTime.UtcNow.AddMinutes(2), 161 | UpVoteCount = 2 162 | }, 163 | new Comment 164 | { 165 | Content = "Some comment 2", 166 | CreatedByUserId = 167 | userIds.ToRandomList(1).Single(), 168 | CreatedOn = DateTime.UtcNow.AddMinutes(1), 169 | } 170 | }, 171 | Answers = new List 172 | { 173 | new Answer 174 | { 175 | Content = "Answer 1 - blah blah blah", 176 | CreatedByUserId = userIds.ToRandomList(1).Single(), 177 | CreatedOn = DateTime.UtcNow.AddMinutes(3), 178 | Vote = new Vote 179 | { 180 | DownVoteCount = 5, 181 | UpVoteCount = 10, 182 | FavoriteCount = 6 183 | } 184 | }, 185 | new Answer 186 | { 187 | Content = "Answer 2 - blah blah blah", 188 | CreatedByUserId = userIds.ToRandomList(1).Single(), 189 | CreatedOn = DateTime.UtcNow.AddMinutes(2), 190 | Vote = new Vote 191 | { 192 | DownVoteCount = 4, 193 | UpVoteCount = 8, 194 | FavoriteCount = 5 195 | } 196 | }, 197 | new Answer 198 | { 199 | Content = "Answer 3 - blah blah blah", 200 | CreatedByUserId = userIds.ToRandomList(1).Single(), 201 | CreatedOn = DateTime.UtcNow.AddMinutes(1), 202 | Vote = new Vote 203 | { 204 | DownVoteCount = 3, 205 | UpVoteCount = 6, 206 | FavoriteCount = 4 207 | } 208 | } 209 | } 210 | }, 211 | new Question 212 | { 213 | Subject = "RavenDb MapReduce over subset of Data", 214 | Content = 215 | "Say I have the given document structure in RavenDb public class Car { public string Manufacturer {get;set;} public int BuildYear {get;set;} public string Colour {get;set;} public", 216 | CreatedOn = DateTime.UtcNow.AddMinutes(4), 217 | Tags = new List {"ravendb", ".net", "c#"}, 218 | CreatedByUserId = userIds.ToRandomList(1).Single(), 219 | NumberOfViews = 44, 220 | Vote = new Vote {DownVoteCount = 4, UpVoteCount = 8, FavoriteCount = 5} 221 | }, 222 | new Question 223 | { 224 | Subject = "RavenDB - retrieving part of document", 225 | Content = 226 | "I am playing with Raven DB for few days and I would like to use it as a storage for my Web chat application. I have document which contains some user data and chat history - which is big collection", 227 | CreatedOn = DateTime.UtcNow.AddMinutes(3), 228 | Tags = new List {"ravendb", ".net", "c#"}, 229 | CreatedByUserId = userIds.ToRandomList(1).Single(), 230 | NumberOfViews = 33, 231 | Vote = new Vote {DownVoteCount = 3, UpVoteCount = 6, FavoriteCount = 4} 232 | }, 233 | new Question 234 | { 235 | Subject = "RavenDB Index on SubClasses", 236 | Content = 237 | "I am trying to create an indexes for ProviderProfileId, Email, and Address1 I have created queries that work, but not indexes. I know the inheriting from List for the collections might be part of", 238 | CreatedOn = DateTime.UtcNow.AddMinutes(2), 239 | Tags = new List {"ravendb", ".net", "c#"}, 240 | CreatedByUserId = userIds.ToRandomList(1).Single(), 241 | NumberOfViews = 22, 242 | Vote = new Vote {DownVoteCount = 2, UpVoteCount = 4, FavoriteCount = 3} 243 | }, 244 | new Question 245 | { 246 | Subject = 247 | "given a list of objects using C# push them to ravendb without knowing which ones already exist", 248 | Content = 249 | "Given 1000 documents with a complex data structure. for e.g. a Car class that has three properties, Make and Model and one Id property. What is the most efficient way in C# to push these documents to", 250 | CreatedOn = DateTime.UtcNow.AddMinutes(1), 251 | Tags = new List {"ravendb", ".net", "c#"}, 252 | CreatedByUserId = userIds.ToRandomList(1).Single(), 253 | NumberOfViews = 11, 254 | Vote = new Vote {DownVoteCount = 1, UpVoteCount = 2, FavoriteCount = 2} 255 | } 256 | }; 257 | } 258 | } 259 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.FakeData/FakeUsers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using CuttingEdge.Conditions; 4 | using FizzWare.NBuilder; 5 | using FizzWare.NBuilder.Generators; 6 | using RavenOverflow.Core.Entities; 7 | 8 | namespace RavenOverflow.FakeData 9 | { 10 | public static class FakeUsers 11 | { 12 | public static User CreateAFakeUser() 13 | { 14 | return Builder 15 | .CreateNew() 16 | .With(x => x.Id = null) 17 | .And(x => x.FullName = string.Format("{0} {1}", GetRandom.FirstName(), GetRandom.LastName())) 18 | .And(x => x.DisplayName = x.FullName.Replace(' ', '.')) 19 | .And(x => x.Email = GetRandom.Email()) 20 | .And(x => x.CreatedOn = GetRandom.DateTime(DateTime.UtcNow.AddMonths(-1), DateTime.UtcNow)) 21 | .And(x => x.Score = GetRandom.PositiveInt(50000)) 22 | .And(x => x.IsActive = GetRandom.Boolean()) 23 | .Build(); 24 | } 25 | 26 | public static ICollection CreateFakeUsers(int numberOfFakeUsers = 20) 27 | { 28 | var fixedUsers = CreateFixedFakeUsers(); 29 | Condition.Requires(numberOfFakeUsers).IsNotLessThan(fixedUsers.Count); 30 | 31 | var fakeUsers = new List(); 32 | fakeUsers.AddRange(fixedUsers); 33 | for (int i = 0; i < numberOfFakeUsers - fixedUsers.Count; i++) 34 | { 35 | fakeUsers.Add(CreateAFakeUser()); 36 | } 37 | 38 | return fakeUsers; 39 | } 40 | 41 | private static List CreateFixedFakeUsers() 42 | { 43 | return new List 44 | { 45 | new User 46 | { 47 | FullName = "Pure Krome", 48 | DisplayName = "Pure.Krome", 49 | Email = "pure.krome@pewpew.xxx", 50 | CreatedOn = new DateTime(2010, 5, 23, 13, 05, 00), 51 | Score = 69, 52 | IsActive = true, 53 | FavoriteTags = new List {"ravendb", "c#", "asp.net-mvc3"} 54 | } 55 | }; 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.FakeData/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("RavenOverflow.FakeData")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("RavenOverflow.FakeData")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2011")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("613e719b-2779-4bb8-a172-a99c18aa2f25")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Code/RavenOverflow.FakeData/RavenOverflow.FakeData.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {71DACF07-CC2C-4AD3-BF61-FF953DE917FF} 9 | Library 10 | Properties 11 | RavenOverflow.FakeData 12 | RavenOverflow.FakeData 13 | v4.5 14 | 512 15 | ..\..\..\RavenOverflow\ 16 | true 17 | 18 | 19 | 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | false 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | false 37 | 38 | 39 | 40 | ..\..\packages\CuttingEdge.Conditions.1.2.0.0\lib\NET35\CuttingEdge.Conditions.dll 41 | 42 | 43 | ..\..\packages\NBuilder.3.0.1.1\lib\FizzWare.NBuilder.dll 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | {58D8E77E-68D3-4623-A558-84B731E7725F} 58 | RavenOverflow.Core 59 | 60 | 61 | 62 | 63 | 70 | -------------------------------------------------------------------------------- /Code/RavenOverflow.FakeData/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Services/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("RavenOverflow.Services")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("RavenOverflow.Services")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2011")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("c74568f8-4f78-4387-a083-253c9fa735a8")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Services/QuestionService.cs: -------------------------------------------------------------------------------- 1 | using CuttingEdge.Conditions; 2 | using Raven.Client; 3 | using RavenOverflow.Core.Entities; 4 | using RavenOverflow.Core.Services; 5 | 6 | namespace RavenOverflow.Services 7 | { 8 | public class QuestionService : RavenDbBaseService, IQuestionService 9 | { 10 | public QuestionService(IDocumentSession documentSession) : base(documentSession) 11 | { 12 | } 13 | 14 | #region IQuestionService Members 15 | 16 | public Question Store(Question question) 17 | { 18 | Condition.Requires(question).IsNotNull(); 19 | 20 | // First, validate the question. 21 | ValidateQuestion(question); 22 | 23 | if (!string.IsNullOrEmpty(question.Id)) 24 | { 25 | var existingQuestion = DocumentSession.Load(question.Id); 26 | if (existingQuestion != null) 27 | { 28 | existingQuestion.Subject = question.Subject; 29 | existingQuestion.Content = question.Content; 30 | existingQuestion.Tags = question.Tags; 31 | existingQuestion.CreatedByUserId = question.CreatedByUserId; 32 | 33 | question = existingQuestion; 34 | } 35 | } 36 | 37 | // Save. 38 | DocumentSession.Store(question); 39 | 40 | return question; 41 | } 42 | 43 | #endregion 44 | 45 | private static void ValidateQuestion(Question question) 46 | { 47 | Condition.Requires(question).IsNotNull(); 48 | 49 | Condition.Requires(question.Subject) 50 | .IsNotNullOrEmpty() 51 | .Evaluate(x => x.Length >= 5, "A subject is required and needs to be at least 5 characters."); 52 | 53 | Condition.Requires(question.Content) 54 | .IsNotNullOrEmpty() 55 | .Evaluate(x => x.Length >= 5, "Some content is required and needs to be at least 5 characters."); 56 | 57 | Condition.Requires(question.Tags) 58 | .IsNotNull() 59 | .IsNotEmpty("At least one valid tag is required."); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Services/RavenDbBaseService.cs: -------------------------------------------------------------------------------- 1 | using CuttingEdge.Conditions; 2 | using Raven.Client; 3 | 4 | namespace RavenOverflow.Services 5 | { 6 | public abstract class RavenDbBaseService 7 | { 8 | protected RavenDbBaseService(IDocumentSession documentSession) 9 | { 10 | Condition.Requires(documentSession).IsNotNull(); 11 | 12 | DocumentSession = documentSession; 13 | } 14 | 15 | public IDocumentSession DocumentSession { get; private set; } 16 | } 17 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Services/RavenOverflow.Services.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {A1F07927-5943-44D6-9FD4-FF36AE6C25DC} 9 | Library 10 | Properties 11 | RavenOverflow.Services 12 | RavenOverflow.Services 13 | v4.5 14 | 512 15 | ..\..\..\RavenOverflow\ 16 | true 17 | 18 | 19 | 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | false 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | false 37 | 38 | 39 | 40 | False 41 | ..\..\packages\AutoMapper.2.2.1\lib\net40\AutoMapper.dll 42 | 43 | 44 | ..\..\packages\CuttingEdge.Conditions.1.2.0.0\lib\NET35\CuttingEdge.Conditions.dll 45 | 46 | 47 | False 48 | ..\..\packages\RavenDB.Client.2.0.2330\lib\net40\Raven.Abstractions.dll 49 | 50 | 51 | False 52 | ..\..\packages\RavenDB.Client.2.0.2330\lib\net40\Raven.Client.Lightweight.dll 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | {58D8E77E-68D3-4623-A558-84B731E7725F} 71 | RavenOverflow.Core 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 87 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Services/UserService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Raven.Client; 5 | using RavenOverflow.Core.Entities; 6 | using RavenOverflow.Core.Services; 7 | 8 | namespace RavenOverflow.Services 9 | { 10 | public class UserService : RavenDbBaseService, IUserService 11 | { 12 | public UserService(IDocumentSession documentSession) : base(documentSession) 13 | { 14 | } 15 | 16 | #region IUserService Members 17 | 18 | public User CreateOrUpdate(OAuthData oAuthData, string userName, string fullName, string email) 19 | { 20 | // Lets find an existing user for the provider OR the email address if the provider doesn't exist. 21 | User user = DocumentSession 22 | .Query() 23 | .SingleOrDefault(x => 24 | x.OAuthData.Any(y => y.Id == oAuthData.Id && 25 | y.OAuthProvider == oAuthData.OAuthProvider)) ?? 26 | DocumentSession 27 | .Query() 28 | .SingleOrDefault(x => x.Email == email); 29 | 30 | if (user != null) 31 | { 32 | // User exists, so lets update the OAuth data, for this user. 33 | if (user.OAuthData != null) 34 | { 35 | OAuthData existingProvider = 36 | user.OAuthData.SingleOrDefault(x => x.OAuthProvider == oAuthData.OAuthProvider); 37 | if (existingProvider != null) 38 | { 39 | user.OAuthData.Remove(existingProvider); 40 | } 41 | } 42 | else 43 | { 44 | user.OAuthData = new List(); 45 | } 46 | 47 | user.OAuthData.Add(oAuthData); 48 | } 49 | else 50 | { 51 | // Ok. No user at all. We create one and store it. 52 | user = new User 53 | { 54 | DisplayName = userName, 55 | Email = email, 56 | Id = null, 57 | FullName = fullName, 58 | CreatedOn = DateTime.UtcNow, 59 | IsActive = true, 60 | OAuthData = new List(), 61 | FavoriteTags = new List {"ravendb", "c#", "asp.net-mvc3"} 62 | }; 63 | user.OAuthData.Add(oAuthData); 64 | } 65 | 66 | DocumentSession.Store(user); 67 | 68 | return user; 69 | } 70 | 71 | #endregion 72 | } 73 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Services/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Tests/ControllerUtilities.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Web.Mvc; 6 | using CuttingEdge.Conditions; 7 | using Moq; 8 | using Raven.Client; 9 | using RavenOverflow.Web.Controllers; 10 | using RavenOverflow.Web.Models.Authentication; 11 | 12 | namespace RavenOverflow.Tests 13 | { 14 | public static class ControllerUtilities 15 | { 16 | // Reference: http://nerddinnerbook.s3.amazonaws.com/Part12.htm 17 | // Yes .. Nerd Dinner to the rescue! and we come full circle... 18 | public static T HomeController(IDocumentSession documentSession, 19 | string userId = null, 20 | string displayName = null, 21 | string[] roles = null) where T : AbstractController, new() 22 | { 23 | Condition.Requires(documentSession); 24 | 25 | // Some fake Authentication stuff. 26 | var customIdentity = new CustomIdentity(userId, displayName); 27 | var customPrincipal = new CustomPrincipal(customIdentity, roles); 28 | 29 | var mockControllerContext = new Mock(); 30 | mockControllerContext.Setup(x => x.HttpContext.User).Returns(customPrincipal); 31 | 32 | var homeController = new T(documentSession) { ControllerContext = mockControllerContext.Object }; 33 | 34 | return homeController; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Tests/Controllers/ControllerUtilities.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | using CuttingEdge.Conditions; 3 | using Moq; 4 | using WorldDomination.Security; 5 | using System.Security.Claims; 6 | 7 | namespace RavenOverflow.Tests.Controllers 8 | { 9 | public static class ControllerUtilities 10 | { 11 | // Reference: http://nerddinnerbook.s3.amazonaws.com/Part12.htm 12 | // Yes .. Nerd Dinner to the rescue! and we come full circle... 13 | public static void SetUpControllerContext(ControllerBase controller, 14 | string userId = null, 15 | string displayName = null) 16 | { 17 | Condition.Requires(controller); 18 | 19 | // Some fake Authentication stuff. 20 | // TODO: Replace with CLAIMS. 21 | var userData = new UserData 22 | { 23 | UserId = userId, 24 | DisplayName = displayName 25 | }; 26 | var customIdentity = new ClaimsIdentity(userData.ToClaims(), "Forms"); 27 | var customPrincipal = new ClaimsPrincipal(customIdentity); 28 | 29 | var mockControllerContext = new Mock(); 30 | mockControllerContext.Setup(x => x.HttpContext.User).Returns(customPrincipal); 31 | 32 | controller.ControllerContext = mockControllerContext.Object; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Tests/Controllers/HomeControllerFacts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Web.Mvc; 6 | using AutoMapper; 7 | using RavenOverflow.Core.Entities; 8 | using RavenOverflow.FakeData; 9 | using RavenOverflow.Web.AutoMapper; 10 | using RavenOverflow.Web.Controllers; 11 | using RavenOverflow.Web.Models.ViewModels; 12 | using RavenOverflow.Web.RavenDb.Indexes; 13 | using WorldDomination.Raven.Tests.Helpers; 14 | using WorldDomination.Security; 15 | using Xunit; 16 | 17 | namespace RavenOverflow.Tests.Controllers 18 | { 19 | // ReSharper disable InconsistentNaming 20 | 21 | public class HomeControllerFacts 22 | { 23 | public class IndexFacts : RavenDbTestBase 24 | { 25 | public IndexFacts() 26 | { 27 | // WebSite requires AutoMapper mappings. 28 | AutoMapperBootstrapper.ConfigureMappings(); 29 | Mapper.AssertConfigurationIsValid(); 30 | } 31 | 32 | [Fact] 33 | public void GivenSomeQuestions_Index_ReturnsTheMostRecentQuestions() 34 | { 35 | // Arrange. 36 | DataToBeSeeded = new List {FakeQuestions.CreateFakeQuestions()}; 37 | IndexesToExecute = new List {typeof (Questions_Search), typeof (RecentPopularTags)}; 38 | 39 | var homeController = new HomeController(DocumentSession, new CustomFormsAuthentication()); 40 | ControllerUtilities.SetUpControllerContext(homeController); 41 | 42 | // Act. 43 | var result = homeController.Index(null, null) as ViewResult; 44 | 45 | // Assert. 46 | Assert.NotNull(result); 47 | 48 | var model = result.Model as IndexViewModel; 49 | Assert.NotNull(model); 50 | Assert.NotNull(model.QuestionListViewModel); 51 | Assert.NotNull(model.QuestionListViewModel.Questions); 52 | Assert.Equal(20, model.QuestionListViewModel.Questions.Count); 53 | 54 | // Make sure all the items are ordered correctly. 55 | DateTime? previousQuestion = null; 56 | foreach (QuestionWithDisplayName question in model.QuestionListViewModel.Questions) 57 | { 58 | if (previousQuestion.HasValue) 59 | { 60 | Assert.True(previousQuestion.Value >= question.CreatedOn); 61 | } 62 | 63 | previousQuestion = question.CreatedOn; 64 | } 65 | 66 | // Now lets test that our fixed questions come back correctly. 67 | List fixedQuestions = FakeQuestions.CreateFakeQuestions(null, 5).ToList(); 68 | for (int i = 0; i < 5; i++) 69 | { 70 | // Can Assert anything except 71 | // * Id (these new fakes haven't been Stored) 72 | // * CreatedByUserId - this is randomized when fakes are created. 73 | // * CreatedOn - these fakes were made AFTER the Stored data. 74 | // ASSUMPTION: the first 5 fixed questions are the first 5 documents in the Document Store. 75 | QuestionWithDisplayName question = model.QuestionListViewModel.Questions[i]; 76 | Assert.Equal(fixedQuestions[i].Subject, question.Subject); 77 | Assert.Equal(fixedQuestions[i].Content, question.Content); 78 | Assert.Equal(fixedQuestions[i].NumberOfViews, question.NumberOfViews); 79 | Assert.Equal(fixedQuestions[i].Vote.DownVoteCount, question.Vote.DownVoteCount); 80 | Assert.Equal(fixedQuestions[i].Vote.FavoriteCount, question.Vote.FavoriteCount); 81 | Assert.Equal(fixedQuestions[i].Vote.UpVoteCount, question.Vote.UpVoteCount); 82 | } 83 | } 84 | 85 | [Fact] 86 | public void GivenSomeQuestions_Index_ReturnsTheMostRecentPopularTagsInTheLast30Days() 87 | { 88 | // Arrange. 89 | DataToBeSeeded = new List {FakeQuestions.CreateFakeQuestions()}; 90 | IndexesToExecute = new List {typeof (Questions_Search), typeof (RecentPopularTags)}; 91 | 92 | var homeController = new HomeController(DocumentSession, new CustomFormsAuthentication()); 93 | ControllerUtilities.SetUpControllerContext(homeController); 94 | 95 | // Act. 96 | var result = homeController.Index(null, null) as ViewResult; 97 | 98 | // Assert. 99 | Assert.NotNull(result); 100 | 101 | var model = result.Model as IndexViewModel; 102 | Assert.NotNull(model); 103 | 104 | Assert.NotNull(model.RecentPopularTags); 105 | Assert.True(model.RecentPopularTags.Count > 0); 106 | 107 | // Make sure all the items are ordered correctly. 108 | int? previousCount = null; 109 | foreach (var keyValuePair in model.RecentPopularTags) 110 | { 111 | if (previousCount.HasValue) 112 | { 113 | Assert.True(previousCount.Value >= keyValuePair.Value); 114 | } 115 | 116 | previousCount = keyValuePair.Value; 117 | } 118 | } 119 | 120 | [Fact] 121 | public void GivenNoAuthenticatedUser_Index_ReturnsFavouriteTagsViewModelWithNoTags() 122 | { 123 | // Arrange. 124 | IndexesToExecute = new List {typeof (Questions_Search), typeof (RecentPopularTags)}; 125 | 126 | // Note: we're faking that no user has been authenticated. 127 | var homeController = new HomeController(DocumentSession, new CustomFormsAuthentication()); 128 | ControllerUtilities.SetUpControllerContext(homeController); 129 | 130 | // Act. 131 | var result = homeController.Index(null, null) as ViewResult; 132 | 133 | // Assert. 134 | Assert.NotNull(result); 135 | 136 | var model = result.Model as IndexViewModel; 137 | Assert.NotNull(model); 138 | 139 | UserTagListViewModel userFavoriteTagListViewModel = model.UserFavoriteTagListViewModel; 140 | Assert.NotNull(userFavoriteTagListViewModel); 141 | 142 | Assert.Equal("Favorite Tags", userFavoriteTagListViewModel.Header); 143 | Assert.Equal("interesting-tags", userFavoriteTagListViewModel.DivId1); 144 | Assert.Equal("interestingtags", userFavoriteTagListViewModel.DivId2); 145 | Assert.Null(userFavoriteTagListViewModel.Tags); 146 | } 147 | 148 | [Fact] 149 | public void GivenSomeQuestionsAndATag_Index_ReturnsAViewResult() 150 | { 151 | // Arrange. 152 | IndexesToExecute = new List {typeof (Questions_Search), typeof (RecentPopularTags)}; 153 | 154 | const string tag = "ravendb"; 155 | var homeController = new HomeController(DocumentSession, new CustomFormsAuthentication()); 156 | ControllerUtilities.SetUpControllerContext(homeController); 157 | 158 | // Act. 159 | var result = homeController.Index(null, tag) as ViewResult; 160 | 161 | // Assert. 162 | Assert.NotNull(result); 163 | 164 | var model = result.Model as IndexViewModel; 165 | Assert.NotNull(model); 166 | Assert.NotNull(model.QuestionListViewModel); 167 | Assert.NotNull(model.QuestionListViewModel.Questions); 168 | 169 | // Make sure each question is tagged with the defined tag-value. 170 | Assert.True(model.QuestionListViewModel.Questions.All(x => x.Tags.Contains(tag))); 171 | } 172 | 173 | [Fact] 174 | public void GivenAnAuthenticatedUserWithSomeFavouriteTags_Index_ReturnsAFavouriteTagsViewModelWithContent() 175 | { 176 | // Arrange. 177 | DataToBeSeeded = new List 178 | { 179 | FakeQuestions.CreateFakeQuestions(), 180 | FakeUsers.CreateFakeUsers() 181 | }; 182 | 183 | IndexesToExecute = new List {typeof (Questions_Search), typeof (RecentPopularTags)}; 184 | 185 | // Note: we're faking that a user has authenticated. 186 | var homeController = new HomeController(DocumentSession, new CustomFormsAuthentication()); 187 | ControllerUtilities.SetUpControllerContext(homeController, displayName: "Pure.Krome"); 188 | 189 | 190 | // Act. 191 | var result = homeController.Index(null, null) as ViewResult; 192 | 193 | // Assert. 194 | Assert.NotNull(result); 195 | 196 | var model = result.Model as IndexViewModel; 197 | Assert.NotNull(model); 198 | 199 | UserTagListViewModel userFavoriteTagListViewModel = model.UserFavoriteTagListViewModel; 200 | Assert.NotNull(userFavoriteTagListViewModel); 201 | 202 | Assert.Equal("Favorite Tags", userFavoriteTagListViewModel.Header); 203 | Assert.Equal("interesting-tags", userFavoriteTagListViewModel.DivId1); 204 | Assert.Equal("interestingtags", userFavoriteTagListViewModel.DivId2); 205 | Assert.NotNull(userFavoriteTagListViewModel.Tags); 206 | Assert.Equal(3, userFavoriteTagListViewModel.Tags.Count); 207 | } 208 | 209 | [Fact] 210 | public void GivenSomeQuestionsAndNoDisplayNameAndNoTags_Index_ReturnsAJsonViewOfMostRecentQuestions() 211 | { 212 | // Arrange. 213 | DataToBeSeeded = new List 214 | { 215 | FakeQuestions.CreateFakeQuestions(new[] {"users/1", "users/2", "users/3"}), 216 | FakeUsers.CreateFakeUsers() 217 | }; 218 | IndexesToExecute = new List {typeof (Questions_Search)}; 219 | 220 | var homeController = new HomeController(DocumentSession, new CustomFormsAuthentication()); 221 | ControllerUtilities.SetUpControllerContext(homeController); 222 | 223 | // Act. 224 | // Note: this should return a list of the 20 most recent. 225 | JsonResult result = homeController.IndexJson(null, null); 226 | 227 | // Assert. 228 | Assert.NotNull(result); 229 | var questions = result.Data as IList; 230 | Assert.NotNull(questions); 231 | Assert.Equal(20, questions.Count); 232 | 233 | // Now lets Make sure each one is ok. 234 | DateTime? previousDate = null; 235 | foreach (QuestionWithDisplayName question in questions) 236 | { 237 | if (previousDate.HasValue) 238 | { 239 | Assert.True(previousDate.Value > question.CreatedOn); 240 | } 241 | 242 | previousDate = question.CreatedOn; 243 | Assert.NotNull(question.DisplayName); 244 | Assert.NotNull(question.Id); 245 | Assert.NotNull(question.CreatedByUserId); 246 | Assert.NotNull(question.Subject); 247 | Assert.NotNull(question.Content); 248 | } 249 | } 250 | } 251 | 252 | public class SearchFacts : RavenDbTestBase 253 | { 254 | public SearchFacts() 255 | { 256 | // WebSite requires AutoMapper mappings. 257 | AutoMapperBootstrapper.ConfigureMappings(); 258 | Mapper.AssertConfigurationIsValid(); 259 | } 260 | 261 | [Fact] 262 | public void GivenSomeQuestionsAndAnExistingTag_Search_ReturnsAListOfTags() 263 | { 264 | // Arrange. 265 | DataToBeSeeded = new List {FakeQuestions.CreateFakeQuestions()}; 266 | IndexesToExecute = new List {typeof (RecentPopularTags)}; 267 | 268 | const string tag = "ravendb"; 269 | var homeController = new HomeController(DocumentSession, new CustomFormsAuthentication()); 270 | ControllerUtilities.SetUpControllerContext(homeController); 271 | 272 | // Act. 273 | var result = homeController.Search(tag) as JsonResult; 274 | 275 | // Assert. 276 | Assert.NotNull(result); 277 | dynamic model = result.Data; 278 | Assert.NotNull(model); 279 | Assert.Equal(1, model.Count); 280 | Assert.Equal("ravendb", model[0]); 281 | } 282 | 283 | [Fact] 284 | public void GivenSomeQuestionsAndAnExistingPartialTag_Search_ReturnsAListOfTaggedQuestions() 285 | { 286 | // Arrange. 287 | DataToBeSeeded = new List {FakeQuestions.CreateFakeQuestions()}; 288 | IndexesToExecute = new List {typeof (RecentPopularTags)}; 289 | 290 | const string tag = "ravne"; // Hardcoded Typo. 291 | var homeController = new HomeController(DocumentSession, new CustomFormsAuthentication()); 292 | ControllerUtilities.SetUpControllerContext(homeController); 293 | 294 | // Act. 295 | var result = homeController.Search(tag) as JsonResult; 296 | 297 | // Assert. 298 | Assert.NotNull(result); 299 | 300 | dynamic model = result.Data; 301 | Assert.NotNull(model); 302 | Assert.Equal(1, model.Count); 303 | Assert.Equal("ravendb", model[0]); 304 | } 305 | } 306 | 307 | public class TagsFacts : RavenDbTestBase 308 | { 309 | public TagsFacts() 310 | { 311 | // WebSite requires AutoMapper mappings. 312 | AutoMapperBootstrapper.ConfigureMappings(); 313 | Mapper.AssertConfigurationIsValid(); 314 | } 315 | 316 | [Fact] 317 | public void GivenSomeQuestionsAndAnExistingTag_Tags_ReturnsAListOfTaggedQuestions() 318 | { 319 | // Arrange. 320 | DataToBeSeeded = new List {FakeQuestions.CreateFakeQuestions()}; 321 | 322 | const string tag = "ravendb"; 323 | var homeController = new HomeController(DocumentSession, new CustomFormsAuthentication()); 324 | ControllerUtilities.SetUpControllerContext(homeController); 325 | 326 | // Act. 327 | var result = homeController.Tag(tag) as JsonResult; 328 | 329 | // Assert. 330 | Assert.NotNull(result); 331 | 332 | dynamic model = result.Data; 333 | Assert.NotNull(model); 334 | 335 | // At least 5 questions are hardcoded to include the RavenDb tag. 336 | Assert.NotNull(model.Questions); 337 | Assert.True(model.Questions.Count >= 5); 338 | Assert.True(model.TotalResults >= 5); 339 | } 340 | } 341 | } 342 | 343 | // ReSharper restore InconsistentNaming 344 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Tests/Controllers/QuestionControllerFacts.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | using AutoMapper; 3 | using RavenOverflow.Services; 4 | using RavenOverflow.Web.Areas.Question.Controllers; 5 | using RavenOverflow.Web.Areas.Question.Models; 6 | using RavenOverflow.Web.AutoMapper; 7 | using WorldDomination.Raven.Tests.Helpers; 8 | using Xunit; 9 | 10 | namespace RavenOverflow.Tests.Controllers 11 | { 12 | // ReSharper disable InconsistentNaming 13 | 14 | public class QuestionControllerFacts 15 | { 16 | public class CreateFacts : RavenDbTestBase 17 | { 18 | public CreateFacts() 19 | { 20 | // WebSite requires AutoMapper mappings. 21 | AutoMapperBootstrapper.ConfigureMappings(); 22 | Mapper.AssertConfigurationIsValid(); 23 | } 24 | 25 | [Fact] 26 | public void GivenAnInvalidQuestion_Create_ReturnsAResultView() 27 | { 28 | // Arrange. 29 | var questionService = new QuestionService(DocumentSession); 30 | var questionsController = new QuestionsController(DocumentSession, questionService); 31 | ControllerUtilities.SetUpControllerContext(questionsController); 32 | var createInputModel = new QuestionInputModel(); 33 | 34 | // Now pretend the model binding raised an error with the input model. 35 | questionsController.ModelState.AddModelError("key", "error message"); 36 | 37 | // Act. 38 | var result = questionsController.Create(createInputModel) as ViewResult; 39 | 40 | // Assert. 41 | Assert.NotNull(result); 42 | Assert.Equal("Create", result.ViewName); 43 | } 44 | 45 | [Fact] 46 | public void GivenAValidQuestionAndNoOneIsLoggedIn_Create_ReturnsAResultView() 47 | { 48 | // Arrange. 49 | var questionService = new QuestionService(DocumentSession); 50 | var questionsController = new QuestionsController(DocumentSession, questionService); 51 | ControllerUtilities.SetUpControllerContext(questionsController); 52 | var createInputModel = new QuestionInputModel(); 53 | 54 | // Act. 55 | var result = questionsController.Create(createInputModel) as ViewResult; 56 | 57 | // Assert. 58 | Assert.NotNull(result); 59 | Assert.Equal("Create", result.ViewName); 60 | } 61 | 62 | [Fact] 63 | public void GivenAValidQuestionAndALoggedInUser_Create_AddsTheQuestionAndRedicects() 64 | { 65 | // Arrange. 66 | var questionService = new QuestionService(DocumentSession); 67 | var questionsController = new QuestionsController(DocumentSession, questionService); 68 | ControllerUtilities.SetUpControllerContext(questionsController, "users/1"); 69 | var createInputModel = 70 | new QuestionInputModel 71 | { 72 | Subject = "aaaad fdds fsd ds", 73 | Content = "sdhfskfhksd sd", 74 | Tags = "ahdakjdh" 75 | }; 76 | 77 | // Act. 78 | var result = questionsController.Create(createInputModel) as RedirectToRouteResult; 79 | 80 | // Assert. 81 | Assert.NotNull(result); 82 | Assert.Equal("Index", result.RouteValues["action"]); 83 | } 84 | } 85 | 86 | // ReSharper restore InconsistentNaming 87 | } 88 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Tests/Controllers/UserControllerFacts.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using RavenOverflow.Web.AutoMapper; 3 | 4 | namespace RavenOverflow.Tests.Controllers 5 | { 6 | // ReSharper disable InconsistentNaming 7 | 8 | public class UserControllerFacts 9 | { 10 | public UserControllerFacts() 11 | { 12 | // WebSite requires AutoMapper mappings. 13 | AutoMapperBootstrapper.ConfigureMappings(); 14 | Mapper.AssertConfigurationIsValid(); 15 | } 16 | } 17 | 18 | // ReSharper restore InconsistentNaming 19 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("RavenOverflow.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("RavenOverflow.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2011")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("f664f9e6-18e3-4edc-b1f2-2466dd7b70d5")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Tests/RavenOverflow.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {9F1968B0-8FF6-4890-AE9E-B391447E9EA4} 9 | Library 10 | Properties 11 | RavenOverflow.Tests 12 | RavenOverflow.Tests 13 | v4.5 14 | 512 15 | ..\..\..\RavenOverflow\ 16 | true 17 | 18 | 19 | 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | false 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | false 37 | 38 | 39 | 40 | False 41 | ..\..\packages\AutoMapper.2.2.1\lib\net40\AutoMapper.dll 42 | 43 | 44 | ..\..\packages\CuttingEdge.Conditions.1.2.0.0\lib\NET35\CuttingEdge.Conditions.dll 45 | 46 | 47 | ..\..\packages\NBuilder.3.0.1.1\lib\FizzWare.NBuilder.dll 48 | 49 | 50 | ..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll 51 | 52 | 53 | ..\..\packages\RavenDB.Client.2.0.2330\lib\net40\Raven.Abstractions.dll 54 | 55 | 56 | ..\..\packages\RavenDB.Embedded.2.0.2330\lib\net40\Raven.Client.Embedded.dll 57 | 58 | 59 | ..\..\packages\RavenDB.Client.2.0.2330\lib\net40\Raven.Client.Lightweight.dll 60 | 61 | 62 | ..\..\packages\RavenDB.Database.2.0.2330\lib\net40\Raven.Database.dll 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | ..\..\packages\WorldDomination.Raven.Client.0.3.3\lib\net40\WorldDomination.Raven.Client.dll 74 | 75 | 76 | ..\..\packages\WorldDomination.Raven.Tests.Helpers.0.3.3\lib\net40\WorldDomination.Raven.Tests.Helpers.dll 77 | 78 | 79 | ..\..\packages\WorldDomination.Security.0.4.0\lib\net45\WorldDomination.Security.dll 80 | 81 | 82 | False 83 | ..\..\packages\xunit.1.9.1\lib\net20\xunit.dll 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | {58D8E77E-68D3-4623-A558-84B731E7725F} 100 | RavenOverflow.Core 101 | 102 | 103 | {71DACF07-CC2C-4AD3-BF61-FF953DE917FF} 104 | RavenOverflow.FakeData 105 | 106 | 107 | {A1F07927-5943-44D6-9FD4-FF36AE6C25DC} 108 | RavenOverflow.Services 109 | 110 | 111 | {44F86C85-B711-4CF5-A161-862EE6E5D160} 112 | RavenOverflow.Web 113 | 114 | 115 | 116 | 117 | 124 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Tests/Services/QuestionServiceFacts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FizzWare.NBuilder; 3 | using Moq; 4 | using Raven.Client; 5 | using RavenOverflow.Core.Entities; 6 | using RavenOverflow.Core.Services; 7 | using RavenOverflow.FakeData; 8 | using RavenOverflow.Services; 9 | using Xunit; 10 | 11 | namespace RavenOverflow.Tests.Services 12 | { 13 | // ReSharper disable InconsistentNaming 14 | 15 | public class QuestionServiceFacts 16 | { 17 | public class CreateFacts 18 | { 19 | [Fact] 20 | public void GivenAnQuestionWithInvalidData_Create_ThrowsAnException() 21 | { 22 | // Arrange. 23 | var question = Builder.CreateNew().Build(); 24 | question.Subject = null; // Forces it to be invalid. 25 | var documentSession = new Mock(); 26 | IQuestionService questionService = new QuestionService(documentSession.Object); 27 | 28 | // Act & Assert. 29 | Assert.Throws(() => questionService.Store(question)); 30 | documentSession.Verify(x => x.Store(It.IsAny()), Times.Never()); 31 | } 32 | 33 | [Fact] 34 | public void GivenAnQuestionWithValidData_Create_StoresAQuestion() 35 | { 36 | // Arrange. 37 | var question = FakeQuestions.CreateAFakeQuestion("someUserId", null); 38 | var documentSession = new Mock(); 39 | IQuestionService questionService = new QuestionService(documentSession.Object); 40 | 41 | // Act. 42 | questionService.Store(question); 43 | 44 | // Assert. 45 | documentSession.Verify(x => x.Store(It.IsAny()), Times.Once()); 46 | } 47 | } 48 | } 49 | 50 | // ReSharper restore InconsistentNaming 51 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/App_Start/MagicalUnicornCustomErrorHandling.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | using System.Web.Routing; 3 | 4 | [assembly: WebActivator.PreApplicationStartMethod( 5 | typeof(RavenOverflow.Web.App_Start.MagicalUnicornCustomErrorHandling), "PreStart")] 6 | 7 | namespace RavenOverflow.Web.App_Start 8 | { 9 | public static class MagicalUnicornCustomErrorHandling 10 | { 11 | public static void PreStart() 12 | { 13 | // Lets wire up our two Error Handling routes, really early. 14 | 15 | // This will be pushed down to route #2. 16 | RouteTable.Routes.Insert(0, new Route("ServerError", 17 | new RouteValueDictionary( 18 | new {controller = "Error", action = "ServerError"}), 19 | new MvcRouteHandler())); 20 | // And now our first route. 21 | RouteTable.Routes.Insert(0, new Route("NotFound", 22 | new RouteValueDictionary( 23 | new {controller = "Error", action = "NotFound"}), 24 | new MvcRouteHandler())); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/App_Start/StructuremapMvc.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | using RavenOverflow.Web.App_Start; 3 | using RavenOverflow.Web.DependencyResolution; 4 | using StructureMap; 5 | using WebActivator; 6 | 7 | [assembly: PreApplicationStartMethod(typeof (StructuremapMvc), "Start")] 8 | 9 | namespace RavenOverflow.Web.App_Start 10 | { 11 | public static class StructuremapMvc 12 | { 13 | public static void Start() 14 | { 15 | IContainer container = IoC.Initialize(); 16 | DependencyResolver.SetResolver(new StructureMapDependencyResolver(container)); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Areas/Question/Controllers/QuestionsController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Mvc; 3 | using AutoMapper; 4 | using CuttingEdge.Conditions; 5 | using Raven.Client; 6 | using RavenOverflow.Core.Services; 7 | using RavenOverflow.Web.Areas.Question.Models; 8 | using RavenOverflow.Web.Controllers; 9 | 10 | namespace RavenOverflow.Web.Areas.Question.Controllers 11 | { 12 | public class QuestionsController : BaseController 13 | { 14 | private readonly IQuestionService _questionService; 15 | 16 | public QuestionsController(IDocumentSession documentSession, IQuestionService questionService) 17 | : base(documentSession) 18 | { 19 | Condition.Requires(questionService).IsNotNull(); 20 | 21 | _questionService = questionService; 22 | } 23 | 24 | [HttpGet] 25 | public ActionResult Create() 26 | { 27 | var inputModel = new QuestionViewModel(ClaimsUser) 28 | { 29 | Header = "Ask a Question" 30 | }; 31 | return View("Create", inputModel); 32 | } 33 | 34 | [HttpPost, Authorize] 35 | public ActionResult Create(QuestionInputModel inputModel) 36 | { 37 | try 38 | { 39 | if (ModelState.IsValid) 40 | { 41 | var question = Mapper.Map(inputModel); 42 | question.CreatedByUserId = ClaimsUser == null ? null : ClaimsUser.Id; 43 | 44 | _questionService.Store(question); 45 | 46 | DocumentSession.SaveChanges(); 47 | 48 | return RedirectToAction("Index", "Home", new {area = ""}); 49 | } 50 | } 51 | catch (Exception exception) 52 | { 53 | ModelState.AddModelError("RuRoh", exception.Message); 54 | } 55 | 56 | var viewModel = new QuestionViewModel(ClaimsUser); 57 | Mapper.Map(inputModel, viewModel); 58 | 59 | return View("Create", viewModel); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Areas/Question/Models/QuestionInputModel.cs: -------------------------------------------------------------------------------- 1 | namespace RavenOverflow.Web.Areas.Question.Models 2 | { 3 | public class QuestionInputModel 4 | { 5 | public string Subject { get; set; } 6 | public string Content { get; set; } 7 | public string Tags { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Areas/Question/Models/QuestionViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Principal; 2 | using RavenOverflow.Web.Models; 3 | 4 | namespace RavenOverflow.Web.Areas.Question.Models 5 | { 6 | public class QuestionViewModel : _LayoutViewModel 7 | { 8 | public QuestionViewModel(ClaimsUser claimsUser) : base(claimsUser) 9 | { 10 | } 11 | 12 | public string Subject { get; set; } 13 | public string Content { get; set; } 14 | public string Tags { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Areas/Question/QuestionAreaRegistration.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | 3 | namespace RavenOverflow.Web.Areas.Question 4 | { 5 | public class QuestionAreaRegistration : AreaRegistration 6 | { 7 | public override string AreaName 8 | { 9 | get { return "Question"; } 10 | } 11 | 12 | public override void RegisterArea(AreaRegistrationContext context) 13 | { 14 | context.MapRoute( 15 | "Question - ask", 16 | "questions/ask", 17 | new { controller = "Questions", action = "Create" } 18 | ); 19 | 20 | context.MapRoute( 21 | "Question_default", 22 | "questions/{action}/{id}", 23 | new { controller = "Questions", action = "Index", id = UrlParameter.Optional } 24 | ); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Areas/Question/Views/Questions/Create.cshtml: -------------------------------------------------------------------------------- 1 | @model RavenOverflow.Web.Areas.Question.Models.QuestionViewModel 2 | @{ 3 | Layout = "~/Views/Shared/_Layout.cshtml"; 4 | } 5 | 6 | @section Header 7 | { 8 | @Model.Header 9 | } 10 | 11 | @section SideBar 12 | { 13 |
How to Ask a Question
14 | } 15 | 16 | @using (Html.BeginForm()) 17 | { 18 |
19 | 20 | 21 | 22 | 25 | 28 | 29 | 30 |
23 | 24 | 26 | @Html.EditorFor(x => x.Subject, new { @class = "ask-title-field edit-field-overlayed", maxlength = "300" }) 27 |
31 |
32 |
33 | @Html.TextAreaFor(x => x.Content, new { @class = "wmd-input processed", cols = "92", rows = "15" }) 34 |
35 |
36 | 37 | @Html.EditorFor(x => x.Tags, new { maxlength = "300"}) 38 |
39 | 40 | if (!@ViewData.ModelState.IsValid) 41 | { 42 | @Html.ValidationSummary("Oops! Your question couldn't be submitted because:", new { @class = "form-error" }) 43 | } 44 | 45 |

46 | 47 |

48 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Areas/Question/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 39 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/AutoMapper/AutoMapperBootstrapper.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using RavenOverflow.Core.Entities; 3 | using RavenOverflow.Web.Areas.Question.Models; 4 | 5 | namespace RavenOverflow.Web.AutoMapper 6 | { 7 | public static class AutoMapperBootstrapper 8 | { 9 | public static void ConfigureMappings() 10 | { 11 | Mapper.CreateMap() 12 | .ForMember(dest => dest.Tags, opt => opt.ResolveUsing()) 13 | .ForMember(dest => dest.Id, opt => opt.Ignore()) 14 | .ForMember(dest => dest.CreatedOn, opt => opt.Ignore()) 15 | .ForMember(dest => dest.CreatedByUserId, opt => opt.Ignore()) 16 | .ForMember(dest => dest.Answers, opt => opt.Ignore()) 17 | .ForMember(dest => dest.NumberOfViews, opt => opt.Ignore()) 18 | .ForMember(dest => dest.Vote, opt => opt.Ignore()) 19 | .ForMember(dest => dest.Comments, opt => opt.Ignore()); 20 | 21 | Mapper.CreateMap() 22 | .ForMember(dest => dest.AuthenticationViewModel, opt => opt.Ignore()) 23 | .ForMember(dest => dest.Header, opt => opt.Ignore()); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/AutoMapper/TagsResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using AutoMapper; 4 | using RavenOverflow.Web.Areas.Question.Models; 5 | 6 | namespace RavenOverflow.Web.AutoMapper 7 | { 8 | public class TagsResolver : ValueResolver> 9 | { 10 | protected override ICollection ResolveCore(QuestionInputModel createInputModel) 11 | { 12 | if (createInputModel == null || createInputModel.Tags == null) 13 | { 14 | return null; 15 | } 16 | 17 | return createInputModel.Tags.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Content/Images/Error/NotFound.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureKrome/RavenOverflow/2e91b036b0da1f30cfaf27aab5c98dfed5ce3b39/Code/RavenOverflow.Web/Content/Images/Error/NotFound.jpg -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Content/Images/Error/ServerError.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureKrome/RavenOverflow/2e91b036b0da1f30cfaf27aab5c98dfed5ce3b39/Code/RavenOverflow.Web/Content/Images/Error/ServerError.jpg -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Content/LeahCulverAvatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureKrome/RavenOverflow/2e91b036b0da1f30cfaf27aab5c98dfed5ce3b39/Code/RavenOverflow.Web/Content/LeahCulverAvatar.png -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Content/logo-ravendb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureKrome/RavenOverflow/2e91b036b0da1f30cfaf27aab5c98dfed5ce3b39/Code/RavenOverflow.Web/Content/logo-ravendb.png -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Controllers/BaseController.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | using CuttingEdge.Conditions; 3 | using Raven.Client; 4 | using RavenOverflow.Web.Models; 5 | 6 | namespace RavenOverflow.Web.Controllers 7 | { 8 | public abstract class BaseController : Controller 9 | { 10 | protected BaseController(IDocumentSession documentSession) 11 | { 12 | Condition.Requires(documentSession).IsNotNull(); 13 | 14 | DocumentSession = documentSession; 15 | } 16 | 17 | protected IDocumentSession DocumentSession { get; private set; } 18 | 19 | protected ClaimsUser ClaimsUser 20 | { 21 | get { return User == null ? null : new ClaimsUser(User); } 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Controllers/ErrorController.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Web.Mvc; 3 | 4 | namespace RavenOverflow.Web.Controllers 5 | { 6 | public class ErrorController : Controller 7 | { 8 | public ActionResult NotFound() 9 | { 10 | Response.StatusCode = (int) HttpStatusCode.NotFound; 11 | return View(); 12 | } 13 | 14 | public ActionResult ServerError() 15 | { 16 | Response.StatusCode = (int) HttpStatusCode.InternalServerError; 17 | return View(); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web.Mvc; 5 | using CuttingEdge.Conditions; 6 | using Raven.Abstractions.Data; 7 | using Raven.Client; 8 | using Raven.Client.Linq; 9 | using RavenOverflow.Core.Entities; 10 | using RavenOverflow.Core.Extensions; 11 | using RavenOverflow.Core.Filters; 12 | using RavenOverflow.Web.Models.ViewModels; 13 | using RavenOverflow.Web.RavenDb.Indexes; 14 | using WorldDomination.Security; 15 | 16 | namespace RavenOverflow.Web.Controllers 17 | { 18 | public class HomeController : BaseController 19 | { 20 | private readonly ICustomFormsAuthentication _customFormsAuthentication; 21 | 22 | public HomeController(IDocumentSession documentSession, 23 | ICustomFormsAuthentication customCustomFormsAuthentication) : base(documentSession) 24 | { 25 | Condition.Requires(customCustomFormsAuthentication).IsNotNull(); 26 | 27 | _customFormsAuthentication = customCustomFormsAuthentication; 28 | } 29 | 30 | [HttpGet] 31 | public ActionResult Authenticate() 32 | { 33 | var userData = new UserData 34 | { 35 | UserId = "users/1", 36 | DisplayName = "Leah Culver", 37 | PictureUri = "/Content/LeahCulverAvatar.png" 38 | }; 39 | _customFormsAuthentication.SignIn(userData); 40 | 41 | return RedirectToAction("Index", "Home", new {area = ""}); 42 | } 43 | 44 | [HttpGet] 45 | public ActionResult SignOut() 46 | { 47 | _customFormsAuthentication.SignOut(); 48 | return RedirectToAction("Index", "Home", new {area = ""}); 49 | } 50 | 51 | [HttpGet] 52 | public ActionResult Index(string displayName, string tag) 53 | { 54 | string header; 55 | 56 | // 1. All the questions, ordered by most recent. 57 | IQueryable questionsQuery = QuestionQuery(tag, out header); 58 | 59 | // 2. Popular Tags for a time period. 60 | // StackOverflow calls it 'recent tags'. 61 | IQueryable recentPopularTags = RecentPopularTagsQuery(); 62 | 63 | // 3. Logged in user information. 64 | IQueryable userQuery = UserQuery(displayName); 65 | 66 | var viewModel = new IndexViewModel(ClaimsUser) 67 | { 68 | Header = header, 69 | QuestionListViewModel = new QuestionListViewModel 70 | { 71 | Questions = questionsQuery.ToList() 72 | }, 73 | RecentPopularTags = recentPopularTags.ToDictionary(x => x.Tag, x => x.Count), 74 | UserFavoriteTagListViewModel = new UserTagListViewModel 75 | { 76 | Header = "Favorite Tags", 77 | DivId1 = "interesting-tags", 78 | DivId2 = "interestingtags", 79 | Tags = userQuery == null 80 | ? null 81 | : (userQuery.SingleOrDefault() ?? 82 | new User()).FavoriteTags 83 | }, 84 | UserIgnoredTagList = new UserTagListViewModel 85 | { 86 | Header = "Ignored Tags", 87 | DivId1 = "ignored-tags", 88 | DivId2 = "ignoredtags", 89 | Tags = null 90 | } 91 | }; 92 | 93 | return View(viewModel); 94 | } 95 | 96 | [HttpGet] 97 | public ActionResult BatchedIndex(string displayName, string tag) 98 | { 99 | string header; 100 | 101 | // 1. All the questions, ordered by most recent. 102 | Lazy> questionsQuery = QuestionQuery(tag, out header).Lazily(); 103 | 104 | // 2. Popular Tags for a time period. 105 | // StackOverflow calls it 'recent tags'. 106 | Lazy> recentPopularTags = RecentPopularTagsQuery().Lazily(); 107 | 108 | // 3. Log in user information. 109 | IQueryable userQuery = UserQuery(displayName); 110 | Lazy> lazyUserQuery = (userQuery != null ? userQuery.Lazily() : null); 111 | 112 | var viewModel = new IndexViewModel(ClaimsUser) 113 | { 114 | Header = header, 115 | QuestionListViewModel = new QuestionListViewModel 116 | { 117 | Questions = questionsQuery.Value.ToList() 118 | }, 119 | RecentPopularTags = recentPopularTags.Value.ToDictionary(x => x.Tag, x => x.Count), 120 | UserFavoriteTagListViewModel = new UserTagListViewModel 121 | { 122 | Header = "Favorite Tags", 123 | DivId1 = "interesting-tags", 124 | DivId2 = "interestingtags", 125 | Tags = lazyUserQuery == null 126 | ? null 127 | : (lazyUserQuery.Value. 128 | SingleOrDefault() ?? 129 | new User()).FavoriteTags 130 | }, 131 | UserIgnoredTagList = new UserTagListViewModel 132 | { 133 | Header = "Ignored Tags", 134 | DivId1 = "ignored-tags", 135 | DivId2 = "ignoredtags", 136 | Tags = null 137 | } 138 | }; 139 | 140 | return View("Index", viewModel); 141 | } 142 | 143 | [HttpGet] 144 | public ActionResult AggressiveIndex(string displayName, string tag) 145 | { 146 | using (DocumentSession.Advanced.DocumentStore.AggressivelyCacheFor(TimeSpan.FromMinutes(1))) 147 | { 148 | string header; 149 | 150 | // 1. All the questions, ordered by most recent. 151 | Lazy> questionsQuery = QuestionQuery(tag, out header).Lazily(); 152 | 153 | // 2. Popular Tags for a time period. 154 | // StackOverflow calls it 'recent tags'. 155 | Lazy> recentPopularTags = RecentPopularTagsQuery().Lazily(); 156 | 157 | // 3. Log in user information. 158 | IQueryable userQuery = UserQuery(displayName); 159 | Lazy> lazyUserQuery = (userQuery != null ? userQuery.Lazily() : null); 160 | 161 | var viewModel = new IndexViewModel(ClaimsUser) 162 | { 163 | Header = header, 164 | QuestionListViewModel = new QuestionListViewModel 165 | { 166 | Questions = questionsQuery.Value.ToList() 167 | }, 168 | RecentPopularTags = 169 | recentPopularTags.Value.ToDictionary(x => x.Tag, x => x.Count), 170 | UserFavoriteTagListViewModel = new UserTagListViewModel 171 | { 172 | Header = "Favorite Tags", 173 | DivId1 = "interesting-tags", 174 | DivId2 = "interestingtags", 175 | Tags = lazyUserQuery == null 176 | ? null 177 | : (lazyUserQuery.Value. 178 | SingleOrDefault() ?? 179 | new User()).FavoriteTags 180 | }, 181 | UserIgnoredTagList = new UserTagListViewModel 182 | { 183 | Header = "Ignored Tags", 184 | DivId1 = "ignored-tags", 185 | DivId2 = "ignoredtags", 186 | Tags = null 187 | } 188 | }; 189 | 190 | return View("Index", viewModel); 191 | } 192 | } 193 | 194 | public ActionResult Tag(string id) 195 | { 196 | RavenQueryStatistics stats; 197 | List questions = DocumentSession.Query() 198 | .Statistics(out stats) 199 | .OrderByCreatedByDescending() 200 | .Take(20) 201 | .Where(x => x.Tags.Any(tag => tag == id)) 202 | .ToList(); 203 | 204 | return Json(new 205 | { 206 | Questions = questions, 207 | stats.TotalResults 208 | }, JsonRequestBehavior.AllowGet); 209 | } 210 | 211 | public ActionResult Facets(string id) 212 | { 213 | var facets = DocumentSession.Query 214 | () 215 | .Where(x => x.LastSeen > DateTime.UtcNow.AddMonths(-1).ToUtcToday()) 216 | .ToFacets("Raven/Facets/Tags"); 217 | 218 | return Json(facets, JsonRequestBehavior.AllowGet); 219 | } 220 | 221 | public ActionResult Search(string term) 222 | { 223 | IRavenQueryable query = DocumentSession 224 | .Query() 225 | .Where(x => x.Tag == term); 226 | 227 | // Does this tag exist? 228 | RecentPopularTags.ReduceResult tag = query.FirstOrDefault(); 229 | 230 | var results = new List(); 231 | 232 | if (tag != null) 233 | { 234 | results.Add(tag.Tag); 235 | } 236 | else 237 | { 238 | // No exact match .. so lets use Suggest. 239 | SuggestionQueryResult suggestedTags = query.Suggest(); 240 | if (suggestedTags.Suggestions.Length > 0) 241 | { 242 | results.AddRange(suggestedTags.Suggestions); 243 | } 244 | } 245 | 246 | return Json(results, JsonRequestBehavior.AllowGet); 247 | } 248 | 249 | public JsonResult IndexJson(string displayName, string tag) 250 | { 251 | string header; 252 | var questions = QuestionQuery(tag, out header).ToList(); 253 | return Json(questions.Count <= 0 ? null : questions); 254 | } 255 | 256 | private IQueryable QuestionQuery(string tag, out string header) 257 | { 258 | header = "Top Questions"; 259 | 260 | IQueryable questionsQuery = DocumentSession.Query() 261 | .OrderByCreatedByDescending() 262 | .Take(20); 263 | 264 | // Filter Questions by Tags? 265 | if (!string.IsNullOrEmpty(tag)) 266 | { 267 | header = "Tagged Questions"; 268 | questionsQuery = questionsQuery 269 | .WithAnyTag(tag); 270 | } 271 | 272 | return questionsQuery.As(); 273 | } 274 | 275 | private IQueryable RecentPopularTagsQuery() 276 | { 277 | IQueryable recentPopularTags = 278 | DocumentSession.Query() 279 | .WithinTheLastMonth(1) 280 | .OrderByCountDescending() 281 | .Take(20); 282 | 283 | return recentPopularTags; 284 | } 285 | 286 | private IQueryable UserQuery(string displayName) 287 | { 288 | string name = displayName ?? User.Identity.Name; 289 | return !string.IsNullOrEmpty(name) ? DocumentSession.Query().WithDisplayName(name) : null; 290 | } 291 | } 292 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/DependencyResolution/AuthenticationRegistry.cs: -------------------------------------------------------------------------------- 1 | using StructureMap.Configuration.DSL; 2 | using WorldDomination.Security; 3 | 4 | namespace RavenOverflow.Web.DependencyResolution 5 | { 6 | public class AuthenticationRegistry : Registry 7 | { 8 | public AuthenticationRegistry() 9 | { 10 | For().Use() 11 | .Named("Custom Forms Authentication instance."); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/DependencyResolution/IoC.cs: -------------------------------------------------------------------------------- 1 | using System.Configuration; 2 | using StructureMap; 3 | 4 | namespace RavenOverflow.Web.DependencyResolution 5 | { 6 | public static class IoC 7 | { 8 | public static IContainer Initialize() 9 | { 10 | ObjectFactory.Initialize(x => 11 | { 12 | x.AddRegistry( 13 | new RavenDbRegistry(ConfigurationManager.ConnectionStrings[0].Name)); 14 | x.AddRegistry(new AuthenticationRegistry()); 15 | x.AddRegistry(new ServiceRegistry()); 16 | }); 17 | return ObjectFactory.Container; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/DependencyResolution/RavenDbRegistry.cs: -------------------------------------------------------------------------------- 1 | using Raven.Client; 2 | using Raven.Client.Document; 3 | using Raven.Client.MvcIntegration; 4 | using RavenOverflow.Web.RavenDb; 5 | using RavenOverflow.Web.RavenDb.Indexes; 6 | using StructureMap.Configuration.DSL; 7 | 8 | namespace RavenOverflow.Web.DependencyResolution 9 | { 10 | public class RavenDbRegistry : Registry 11 | { 12 | public RavenDbRegistry(string connectionStringName) 13 | { 14 | For() 15 | .Singleton() 16 | .Use(x => 17 | { 18 | var documentStore = new DocumentStore {ConnectionStringName = connectionStringName}; 19 | documentStore.InitializeWithDefaults(); 20 | 21 | // Create any Facets. 22 | RavenFacetTags.CreateFacets(documentStore); 23 | 24 | // Wire up the RavenDb profiler. 25 | // This is -very- MVC specific, of course. You wouldn't find this in the Tests. 26 | RavenProfiler.InitializeFor(documentStore); 27 | 28 | return documentStore; 29 | } 30 | ) 31 | .Named("RavenDB Document Store."); 32 | 33 | For() 34 | .HttpContextScoped() 35 | .Use(x => 36 | { 37 | var documentStore = x.GetInstance(); 38 | return documentStore.OpenSession(); 39 | }) 40 | .Named("RavenDb Session -> per Http Request."); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/DependencyResolution/ServiceRegistry.cs: -------------------------------------------------------------------------------- 1 | using RavenOverflow.Core.Services; 2 | using RavenOverflow.Services; 3 | using StructureMap.Configuration.DSL; 4 | 5 | namespace RavenOverflow.Web.DependencyResolution 6 | { 7 | public class ServiceRegistry : Registry 8 | { 9 | public ServiceRegistry() 10 | { 11 | For().Use() 12 | .Named("Question service."); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/DependencyResolution/StructureMapDependencyResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web.Mvc; 5 | using StructureMap; 6 | 7 | namespace RavenOverflow.Web.DependencyResolution 8 | { 9 | public class StructureMapDependencyResolver : IDependencyResolver 10 | { 11 | private readonly IContainer _container; 12 | 13 | public StructureMapDependencyResolver(IContainer container) 14 | { 15 | _container = container; 16 | } 17 | 18 | #region IDependencyResolver Members 19 | 20 | public object GetService(Type serviceType) 21 | { 22 | if (serviceType == null) return null; 23 | 24 | return serviceType.IsAbstract || serviceType.IsInterface 25 | ? _container.TryGetInstance(serviceType) 26 | : _container.GetInstance(serviceType); 27 | } 28 | 29 | public IEnumerable GetServices(Type serviceType) 30 | { 31 | return _container.GetAllInstances(serviceType).Cast(); 32 | } 33 | 34 | #endregion 35 | } 36 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="RavenOverflow.Web.MvcApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Mvc; 3 | using System.Web.Routing; 4 | using RavenOverflow.Web.AutoMapper; 5 | 6 | namespace RavenOverflow.Web 7 | { 8 | // ReSharper disable InconsistentNaming 9 | 10 | public class MvcApplication : HttpApplication 11 | { 12 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) 13 | { 14 | //filters.Add(new HandleErrorAttribute()); 15 | } 16 | 17 | public static void RegisterRoutes(RouteCollection routes) 18 | { 19 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 20 | routes.IgnoreRoute("{*favicon}", new {favicon = @"(.*/)?favicon.ico(/.*)?"}); 21 | 22 | routes.MapRoute( 23 | "Default", // Route name 24 | "{controller}/{action}/{id}", // URL with parameters 25 | new {controller = "Home", action = "Index", id = UrlParameter.Optional} // Parameter defaults 26 | ); 27 | } 28 | 29 | private static void RegisterRazorViewEngine() 30 | { 31 | ViewEngines.Engines.Clear(); 32 | ViewEngines.Engines.Add(new RazorViewEngine()); 33 | } 34 | 35 | protected void Application_Start() 36 | { 37 | AreaRegistration.RegisterAllAreas(); 38 | 39 | RegisterGlobalFilters(GlobalFilters.Filters); 40 | 41 | RegisterRazorViewEngine(); 42 | 43 | RegisterRoutes(RouteTable.Routes); 44 | 45 | // Configure AutoMapper mappings. 46 | AutoMapperBootstrapper.ConfigureMappings(); 47 | } 48 | } 49 | 50 | // ReSharper restore InconsistentNaming 51 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Models/ClaimsUser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Claims; 3 | using System.Security.Principal; 4 | using CuttingEdge.Conditions; 5 | using WorldDomination.Security; 6 | 7 | namespace RavenOverflow.Web.Models 8 | { 9 | public class ClaimsUser 10 | { 11 | public ClaimsUser(IPrincipal principal) 12 | { 13 | Condition.Requires(principal).IsNotNull(); 14 | 15 | var claimsPrincipal = principal as ClaimsPrincipal; 16 | Condition 17 | .WithExceptionOnFailure() 18 | .Requires(claimsPrincipal).IsNotNull("A principal argument was provided, but it needs to be a 'ClaimsPrincipal'."); 19 | 20 | IsAuthenticated = claimsPrincipal.Identity.IsAuthenticated; 21 | 22 | if (claimsPrincipal.HasClaim(x => x.Type == ClaimTypes.Uri)) 23 | { 24 | Id = claimsPrincipal.FindFirst(x => x.Type == ClaimTypes.Uri).Value; 25 | } 26 | 27 | if (claimsPrincipal.HasClaim(x => x.Type == ClaimTypes.Name)) 28 | { 29 | Name = claimsPrincipal.FindFirst(x => x.Type == ClaimTypes.Name).Value; 30 | } 31 | 32 | if (claimsPrincipal.HasClaim(x => x.Type == CustomClaimsTypes.PictureUri)) 33 | { 34 | PictureUri = claimsPrincipal.FindFirst(x => x.Type == CustomClaimsTypes.PictureUri).Value; 35 | } 36 | } 37 | 38 | public bool IsAuthenticated { get; private set; } 39 | public string Id { get; private set; } 40 | public string Name { get; private set; } 41 | public string PictureUri { get; private set; } 42 | } 43 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Models/HtmlExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace RavenOverflow.Web.Models 2 | { 3 | public static class HtmlExtensions 4 | { 5 | public static string ToSimplifiedNumberText(this int value) 6 | { 7 | return value < 1000 ? value.ToString() : string.Format("{0}k", value/1000); 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Models/ViewModels/AuthenticationViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace RavenOverflow.Web.Models.ViewModels 2 | { 3 | public class AuthenticationViewModel 4 | { 5 | public AuthenticationViewModel(ClaimsUser claimsUser) 6 | { 7 | if (claimsUser == null) 8 | { 9 | IsAuthenticated = false; 10 | return; 11 | } 12 | 13 | IsAuthenticated = claimsUser.IsAuthenticated; 14 | Name = claimsUser.Name; 15 | PictureUri = claimsUser.PictureUri; 16 | } 17 | 18 | public bool IsAuthenticated { get; private set; } 19 | public string Name { get; private set; } 20 | public string PictureUri { get; private set; } 21 | } 22 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Models/ViewModels/IndexViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace RavenOverflow.Web.Models.ViewModels 4 | { 5 | public class IndexViewModel : _LayoutViewModel 6 | { 7 | public IndexViewModel(ClaimsUser claimsUser) : base(claimsUser) 8 | { 9 | } 10 | 11 | public QuestionListViewModel QuestionListViewModel { get; set; } 12 | public IDictionary RecentPopularTags { get; set; } 13 | public UserTagListViewModel UserFavoriteTagListViewModel { get; set; } 14 | public UserTagListViewModel UserIgnoredTagList { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Models/ViewModels/QuestionListViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace RavenOverflow.Web.Models.ViewModels 4 | { 5 | public class QuestionListViewModel 6 | { 7 | public IList Questions { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Models/ViewModels/QuestionWithDisplayName.cs: -------------------------------------------------------------------------------- 1 | using RavenOverflow.Core.Entities; 2 | 3 | namespace RavenOverflow.Web.Models.ViewModels 4 | { 5 | public class QuestionWithDisplayName : Question 6 | { 7 | public string DisplayName { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Models/ViewModels/TagListViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace RavenOverflow.Web.Models.ViewModels 4 | { 5 | public class TagListViewModel 6 | { 7 | public ICollection Tags { get; set; } 8 | public bool IsUserTags { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Models/ViewModels/UserTagListViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace RavenOverflow.Web.Models.ViewModels 4 | { 5 | public class UserTagListViewModel 6 | { 7 | public string Header { get; set; } 8 | public string DivId1 { get; set; } 9 | public string DivId2 { get; set; } 10 | public IList Tags { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Models/_LayoutViewModel.cs: -------------------------------------------------------------------------------- 1 | using RavenOverflow.Web.Models.ViewModels; 2 | 3 | namespace RavenOverflow.Web.Models 4 | { 5 | // ReSharper disable InconsistentNaming 6 | 7 | public class _LayoutViewModel 8 | { 9 | public _LayoutViewModel(ClaimsUser claimsUser) 10 | { 11 | if (claimsUser != null) 12 | { 13 | AuthenticationViewModel = new AuthenticationViewModel(claimsUser); 14 | } 15 | } 16 | 17 | public AuthenticationViewModel AuthenticationViewModel { get; private set; } 18 | public string Header { get; set; } 19 | } 20 | 21 | // ReSharper restore InconsistentNaming 22 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Models/_MainNavigationViewModel.cs: -------------------------------------------------------------------------------- 1 | using RavenOverflow.Web.Models.ViewModels; 2 | 3 | namespace RavenOverflow.Web.Models 4 | { 5 | // ReSharper disable InconsistentNaming 6 | 7 | public class _MainNavigationViewModel 8 | { 9 | public AuthenticationViewModel AuthenticationViewModel { get; set; } 10 | } 11 | 12 | // ReSharper restore InconsistentNaming 13 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("RavenOverflow.Web")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("RavenOverflow.Web")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2011")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("6e92c3fd-2153-4b2d-9413-2896d40dbfbc")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | 37 | 38 | // Enable dynamic unit testing of controller results. 39 | [assembly: InternalsVisibleTo("RavenOverflow.Tests")] -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/RavenDb/DocumentStoreExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.Composition.Hosting; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading; 8 | using CuttingEdge.Conditions; 9 | using Raven.Abstractions.Data; 10 | using Raven.Client; 11 | using Raven.Client.Indexes; 12 | using RavenOverflow.Web.RavenDb.Indexes; 13 | 14 | namespace RavenOverflow.Web.RavenDb 15 | { 16 | public static class DocumentStoreExtensions 17 | { 18 | public static void InitializeWithDefaults(this IDocumentStore documentStore) 19 | { 20 | documentStore.InitializeWithDefaults(true, null); 21 | } 22 | 23 | public static void InitializeWithDefaults(this IDocumentStore documentStore, bool isDataToBeSeeded, 24 | IList indexesToExecute) 25 | { 26 | Condition.Requires(documentStore).IsNotNull(); 27 | 28 | // Default initializtion; 29 | documentStore.Initialize(); 30 | 31 | // Index initialisation. 32 | if (indexesToExecute != null) 33 | { 34 | Type[] indexes = (from type in indexesToExecute 35 | where type.IsSubclassOf(typeof (AbstractIndexCreationTask)) 36 | select type).ToArray(); 37 | 38 | IndexCreation.CreateIndexes(new CompositionContainer(new TypeCatalog(indexes)), documentStore); 39 | } 40 | else 41 | { 42 | IndexCreation.CreateIndexes(typeof (RecentPopularTags).Assembly, documentStore); 43 | } 44 | 45 | // Create our Seed Data (if required). 46 | // NOTE: This would be handled differently if it was a -real- production system. 47 | // Like, wrapping this called in a #if RELEASE #endif, for example. 48 | if (isDataToBeSeeded) 49 | { 50 | HelperUtilities.CreateSeedData(documentStore); 51 | } 52 | 53 | // Now lets check to make sure there are now errors. 54 | documentStore.AssertDocumentStoreErrors(); 55 | } 56 | 57 | public static void AssertDocumentStoreErrors(this IDocumentStore documentStore) 58 | { 59 | if (documentStore == null) 60 | { 61 | throw new ArgumentNullException("documentStore"); 62 | } 63 | 64 | ServerError[] errors = documentStore.DatabaseCommands.GetStatistics().Errors; 65 | if (errors == null || errors.Length <= 0) 66 | { 67 | return; 68 | } 69 | 70 | // We have some Errors. NOT. GOOD. :( 71 | var errorMessages = new StringBuilder(); 72 | foreach (ServerError serverError in errors) 73 | { 74 | string errorMessage = string.Format("Document: {0}; Index: {1}; Error: {2}", 75 | string.IsNullOrEmpty(serverError.Document) 76 | ? "No Document Id" 77 | : serverError.Document, 78 | string.IsNullOrEmpty(serverError.Index) 79 | ? "No Index" 80 | : serverError.Index, 81 | string.IsNullOrEmpty(serverError.Error) 82 | ? "No Error message .. err??" 83 | : serverError.Error); 84 | 85 | 86 | Debug.WriteLine(errorMessage); 87 | errorMessages.AppendLine(errorMessage); 88 | } 89 | 90 | throw new InvalidOperationException("DocumentStore has some errors. Dast is nict gut."); 91 | } 92 | 93 | public static void WaitForStaleIndexesToComplete(this IDocumentStore documentStore) 94 | { 95 | while (documentStore.DatabaseCommands.GetStatistics().StaleIndexes.Length != 0) 96 | { 97 | Thread.Sleep(50); 98 | } 99 | } 100 | } 101 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/RavenDb/HelperUtilities.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using CuttingEdge.Conditions; 5 | using Raven.Client; 6 | using RavenOverflow.Core.Entities; 7 | using RavenOverflow.FakeData; 8 | 9 | namespace RavenOverflow.Web.RavenDb 10 | { 11 | public static class HelperUtilities 12 | { 13 | public static void CreateSeedData(IDocumentStore documentStore) 14 | { 15 | Condition.Requires(documentStore).IsNotNull(); 16 | 17 | using (IDocumentSession documentSession = documentStore.OpenSession()) 18 | { 19 | // First, check to make sure we don't have any data. 20 | var user = documentSession.Load(1); 21 | if (user != null) 22 | { 23 | // ooOooo! we have a user, so it's assumed we actually have some seeded data. 24 | return; 25 | } 26 | 27 | // We have no users, so it's assumed we therefore have no data at all. 28 | // So lets fake some up :) 29 | 30 | // Users. 31 | ICollection users = FakeUsers.CreateFakeUsers(50); 32 | StoreFakeEntities(users, documentSession); 33 | 34 | // Questions. 35 | ICollection questions = FakeQuestions.CreateFakeQuestions(users.Select(x => x.Id).ToList()); 36 | StoreFakeEntities(questions, documentSession); 37 | 38 | documentSession.SaveChanges(); 39 | 40 | // Make sure all our indexes are not stale. 41 | documentStore.WaitForStaleIndexesToComplete(); 42 | } 43 | } 44 | 45 | public static void StoreFakeEntities(IEnumerable entities, IDocumentSession session) 46 | { 47 | // Dont' use Condition.Requires for entities becuase it might enumerate through it. 48 | if (entities == null) 49 | { 50 | throw new ArgumentNullException("entities"); 51 | } 52 | 53 | Condition.Requires(session).IsNotNull(); 54 | 55 | foreach (RootAggregate entity in entities) 56 | { 57 | session.Store(entity); 58 | } 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/RavenDb/Indexes/Questions_Search.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Raven.Client.Indexes; 3 | using RavenOverflow.Core.Entities; 4 | 5 | namespace RavenOverflow.Web.RavenDb.Indexes 6 | { 7 | public class Questions_Search : AbstractIndexCreationTask 8 | { 9 | public Questions_Search() 10 | { 11 | Map = questions => from q in questions 12 | select new 13 | { 14 | q.CreatedOn, 15 | q.Tags 16 | }; 17 | 18 | TransformResults = (database, questions) => from q in questions 19 | let user = database.Load(q.CreatedByUserId) 20 | select new 21 | { 22 | q.Answers, 23 | q.Comments, 24 | q.Content, 25 | q.CreatedByUserId, 26 | user.DisplayName, 27 | q.CreatedOn, 28 | q.Id, 29 | q.NumberOfViews, 30 | q.Subject, 31 | q.Tags, 32 | q.Vote 33 | }; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/RavenDb/Indexes/RavenFacetTags.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Raven.Abstractions.Data; 3 | using Raven.Client; 4 | 5 | namespace RavenOverflow.Web.RavenDb.Indexes 6 | { 7 | public static class RavenFacetTags 8 | { 9 | public static void CreateFacets(IDocumentStore documentStore) 10 | { 11 | using (IDocumentSession session = documentStore.OpenSession()) 12 | { 13 | session.Store(new FacetSetup 14 | { 15 | Id = "Raven/Facets/Tags", 16 | Facets = new List 17 | { 18 | new Facet 19 | { 20 | Mode = FacetMode.Default, 21 | Name = "Tag" 22 | } 23 | } 24 | }); 25 | session.SaveChanges(); 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/RavenDb/Indexes/RecentPopularTags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Raven.Abstractions.Indexing; 4 | using Raven.Client.Indexes; 5 | using Raven.Client.Linq; 6 | using RavenOverflow.Core.Entities; 7 | using RavenOverflow.Core.Extensions; 8 | 9 | namespace RavenOverflow.Web.RavenDb.Indexes 10 | { 11 | public class RecentPopularTags : AbstractIndexCreationTask 12 | { 13 | public RecentPopularTags() 14 | { 15 | Map = questions => from question in questions 16 | from tag in question.Tags 17 | select new 18 | { 19 | Tag = tag, 20 | Count = 1, 21 | LastSeen = (DateTimeOffset) question.CreatedOn 22 | }; 23 | 24 | Reduce = results => from result in results 25 | group result by result.Tag 26 | into g 27 | select new 28 | { 29 | Tag = g.Key, 30 | Count = g.Sum(x => x.Count), 31 | LastSeen = g.Max(x => (DateTimeOffset)x.LastSeen) 32 | }; 33 | 34 | Index(x => x.Tag, FieldIndexing.Analyzed); 35 | 36 | Sort(x => x.Count, Raven.Abstractions.Indexing.SortOptions.Short); 37 | } 38 | 39 | #region Nested type: ReduceResult 40 | 41 | public class ReduceResult 42 | { 43 | public string Tag { get; set; } 44 | public short Count { get; set; } 45 | public DateTimeOffset LastSeen { get; set; } 46 | 47 | public override string ToString() 48 | { 49 | return string.Format("{0} : {1} : {2}", Tag, Count, LastSeen); 50 | } 51 | } 52 | 53 | #endregion 54 | } 55 | 56 | #region Extensions 57 | 58 | public static class Extensions 59 | { 60 | public static IRavenQueryable WithinTheLastMonth( 61 | this IRavenQueryable query, int numberOfMonths) 62 | { 63 | return query.Where(x => x.LastSeen > DateTime.UtcNow.AddMonths(numberOfMonths*(-1)).ToUtcToday()); 64 | } 65 | 66 | public static IRavenQueryable OrderByCountDescending( 67 | this IRavenQueryable query) 68 | { 69 | return query.OrderByDescending(x => x.Count); 70 | } 71 | } 72 | 73 | #endregion 74 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/RavenDb/Indexes/RecentPopularTagsMapOnly.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Raven.Client.Indexes; 4 | using RavenOverflow.Core.Entities; 5 | 6 | namespace RavenOverflow.Web.RavenDb.Indexes 7 | { 8 | public class RecentPopularTagsMapOnly : AbstractIndexCreationTask 9 | { 10 | public RecentPopularTagsMapOnly() 11 | { 12 | Map = questions => from question in questions 13 | from tag in question.Tags 14 | select new 15 | { 16 | Tag = tag, 17 | LastSeen = (DateTimeOffset) question.CreatedOn 18 | }; 19 | } 20 | 21 | #region Nested type: ReduceResult 22 | 23 | public class ReduceResult 24 | { 25 | public string Tag { get; set; } 26 | public int Count { get; set; } 27 | public DateTimeOffset LastSeen { get; set; } 28 | } 29 | 30 | #endregion 31 | } 32 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/RavenOverflow.Web.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 8 | 9 | 2.0 10 | {44F86C85-B711-4CF5-A161-862EE6E5D160} 11 | {E53F8FEA-EAE0-44A6-8774-FFD645390401};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} 12 | Library 13 | Properties 14 | RavenOverflow.Web 15 | RavenOverflow.Web 16 | v4.5 17 | false 18 | true 19 | ..\..\..\RavenOverflow\ 20 | true 21 | 22 | 23 | 24 | 25 | 4.0 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | true 34 | full 35 | false 36 | bin\ 37 | DEBUG;TRACE 38 | prompt 39 | 4 40 | false 41 | 42 | 43 | pdbonly 44 | true 45 | bin\ 46 | TRACE 47 | prompt 48 | 4 49 | false 50 | 51 | 52 | 53 | False 54 | ..\..\packages\AutoMapper.2.2.1\lib\net40\AutoMapper.dll 55 | 56 | 57 | ..\..\packages\CuttingEdge.Conditions.1.2.0.0\lib\NET35\CuttingEdge.Conditions.dll 58 | 59 | 60 | False 61 | ..\..\packages\RavenDB.Client.2.0.2330\lib\net40\Raven.Abstractions.dll 62 | 63 | 64 | False 65 | ..\..\packages\RavenDB.Client.2.0.2330\lib\net40\Raven.Client.Lightweight.dll 66 | 67 | 68 | False 69 | ..\..\packages\RavenDB.Client.MvcIntegration.2.0.2330\lib\net40\Raven.Client.MvcIntegration.dll 70 | 71 | 72 | ..\..\packages\RestSharp.104.1\lib\net4\RestSharp.dll 73 | 74 | 75 | False 76 | ..\..\packages\structuremap.2.6.4.1\lib\net40\StructureMap.dll 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | False 96 | ..\..\packages\WebActivator.1.5\lib\net40\WebActivator.dll 97 | 98 | 99 | ..\..\packages\WorldDomination.Raven.Client.0.3.3\lib\net40\WorldDomination.Raven.Client.dll 100 | 101 | 102 | ..\..\packages\WorldDomination.Security.0.4.0\lib\net45\WorldDomination.Security.dll 103 | 104 | 105 | False 106 | ..\..\packages\WorldDomination.Web.Authentication.0.19.0-Csrf-PewPew-4\lib\net40\WorldDomination.Web.Authentication.dll 107 | 108 | 109 | False 110 | ..\..\packages\WorldDomination.Web.Authentication.Mvc.0.19.0-Csrf-PewPew-4\lib\net40\WorldDomination.Web.Authentication.Mvc.dll 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | Global.asax 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | Web.config 160 | 161 | 162 | Web.config 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | {58D8E77E-68D3-4623-A558-84B731E7725F} 179 | RavenOverflow.Core 180 | 181 | 182 | {71DACF07-CC2C-4AD3-BF61-FF953DE917FF} 183 | RavenOverflow.FakeData 184 | 185 | 186 | {A1F07927-5943-44D6-9FD4-FF36AE6C25DC} 187 | RavenOverflow.Services 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 10.0 237 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 238 | 239 | 240 | 241 | 242 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | True 256 | True 257 | 52263 258 | / 259 | http://localhost:52263/ 260 | False 261 | False 262 | 263 | 264 | False 265 | 266 | 267 | 268 | 269 | 270 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Views/Error/NotFound.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "NotFound"; 3 | Layout = "~/Views/Shared/_ErrorLayout.cshtml"; 4 | } 5 | 6 |

404 Not Found

7 | 8 |

zomg it's a 404 not found error page!

9 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Views/Error/ServerError.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "ServerError"; 3 | Layout = "~/Views/Shared/_ErrorLayout.cshtml"; 4 | } 5 | 6 |

500 Server Error

7 | 8 |

9 | Sad Panda makes it a 500 Server Error :~( 10 |

-------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using RavenOverflow.Web.Models.ViewModels 2 | @model IndexViewModel 3 | @{ 4 | Layout = "~/Views/Shared/_Layout.cshtml"; 5 | } 6 | 7 | @section Header 8 | { 9 | @Model.Header 10 | } 11 | 12 | @section SideBar 13 | { 14 | @if (Model != null) 15 | { 16 | Html.RenderPartial("_UserTagList", Model.UserFavoriteTagListViewModel); 17 | Html.RenderPartial("_UserTagList", Model.UserIgnoredTagList); 18 | Html.RenderPartial("_TagListVertical", Model.RecentPopularTags); 19 | } 20 | } 21 | 22 | @if (Model == null) 23 | { 24 |

No questions have been asked.

25 | } 26 | else 27 | { 28 | Html.RenderPartial("_QuestionList", Model.QuestionListViewModel); 29 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = null; 3 | } 4 | 5 | 6 | 7 | 8 | Error 9 | 10 | 11 |

12 | Sorry, an error occurred while processing your request. 13 |

14 | 15 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Views/Shared/_Authentication.cshtml: -------------------------------------------------------------------------------- 1 | @model RavenOverflow.Web.Models.ViewModels.AuthenticationViewModel 2 | 3 | @if (Model != null && Model.IsAuthenticated) 4 | { 5 | @:Welcome @Model.Name! 6 | if (!string.IsNullOrEmpty(Model.PictureUri)) 7 | { 8 | @Model.Name 9 | } 10 |
    11 |
  • Settings
  • 12 |
  • @Html.ActionLink("LogOff", "SignOut", "Home", new { Area = ""}, null)
  • 13 |
14 | } 15 | else 16 | { 17 |
    18 |
  • @Html.ActionLink("Log On", "Authenticate", "Home", new {Area = "", returnUrl = HttpContext.Current.Request.RawUrl}, null)
  • 19 |
20 | } 21 |
-------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Views/Shared/_ErrorLayout.cshtml: -------------------------------------------------------------------------------- 1 | @using RavenOverflow.Web.Models 2 | @model _LayoutViewModel 3 | 4 | 5 | 6 | Raven Overflow 7 | 8 | 9 | 10 | @RenderBody() 11 | 12 | 13 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | @using RavenOverflow.Web.Models 2 | @model _LayoutViewModel 3 | 4 | 5 | 6 | Raven Overflow 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | @Raven.Client.MvcIntegration.RavenProfiler.CurrentRequestSessions(); 20 | 21 | 22 | 23 | @Html.Partial("_MainNavigation", new _MainNavigationViewModel { AuthenticationViewModel = Model.AuthenticationViewModel}) 24 | 25 |
26 |
27 |
28 |
29 | 54 | 55 |
56 |
57 |
58 |

@RenderSection("Header")

59 |
60 | interesting | featured | hot | week | month 61 |
62 |
63 |
64 | @RenderBody() 65 |
66 | 67 |

Looking for more? Goto the real Stack Overflow site.

68 |
69 | 70 | 73 |
74 |
75 | 76 | 77 | @RenderSection("JavaScript", false); 78 | 79 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Views/Shared/_MainNavigation.cshtml: -------------------------------------------------------------------------------- 1 | @using RavenOverflow.Web.Models 2 | @model _MainNavigationViewModel 3 |
4 | @{ 5 | int number = Model.AuthenticationViewModel != null && Model.AuthenticationViewModel.IsAuthenticated ? 3 : 2; 6 | } 7 |

@Html.ActionLink("Index - " + number + " DB roundtrips", "Index", "Home", new {Area = ""}, new {}) || 8 | @Html.ActionLink("BatchedIndex - 1 DB roundtrip", "BatchedIndex", "Home", new {Area = ""}, new {}) || 9 | @Html.ActionLink("AggressiveIndex - 1 DB roundtrip + Clientside Caching", "AggressiveIndex", "Home", new {Area = ""}, new {}) 10 |

11 |
12 | 13 |
-------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Views/Shared/_QuestionList.cshtml: -------------------------------------------------------------------------------- 1 | @using RavenOverflow.Web.Models.ViewModels 2 | @using RavenOverflow.Web.Models 3 | @model QuestionListViewModel 4 | 5 | @if (Model == null || Model.Questions == null || Model.Questions.Count <= 0) 6 | { 7 |

No questions have been asked.

8 | } 9 | else 10 | { 11 | foreach (var question in Model.Questions) 12 | { 13 |
14 |
15 |
@((question.Vote == null ? 0 : question.Vote.UpVoteCount - question.Vote.DownVoteCount).ToSimplifiedNumberText())
16 |
votes
17 |
18 | 19 |
20 |
@((question.Answers != null ? question.Answers.Count : 0).ToSimplifiedNumberText())
21 |
answers
22 | 23 |
24 | 25 |
26 |
@question.NumberOfViews.ToSimplifiedNumberText()
27 |
views
28 |
29 | 30 |
31 |

@question.Subject

32 | 33 | @Html.Partial("_QuestionTagList", question.Tags) 34 | 35 | 36 |
37 | @question.CreatedOn.ToShortDateString() @question.CreatedOn.ToShortTimeString() 38 | @question.DisplayName 39 | ?? 40 |
41 |
42 |
43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Views/Shared/_QuestionTagList.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Text 2 | @using RavenOverflow.Web.Models.ViewModels 3 | @model ICollection 4 | 5 | @if (Model == null || Model.Count <= 0) 6 | { 7 |

No tags

8 | } 9 | else 10 | { 11 | var tags = new StringBuilder(); 12 | foreach (string tag in Model) 13 | { 14 | tags.AppendFormat("{0}{1}{2}", tags.Length > 0 ? " " : string.Empty, "t-", tag); 15 | } 16 | 17 |
18 | @Html.Partial("_TagList", new TagListViewModel 19 | { 20 | IsUserTags = false, 21 | Tags = Model 22 | }); 23 |
24 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Views/Shared/_TagList.cshtml: -------------------------------------------------------------------------------- 1 | @using RavenOverflow.Web.Models.ViewModels 2 | @model TagListViewModel 3 | 4 | @if (Model == null || Model.Tags == null || Model.Tags.Count <= 0) 5 | { 6 |

No tags

7 | } 8 | else 9 | { 10 | bool isFirstTag = true; 11 | foreach (string tag in Model.Tags) 12 | { 13 | if (!isFirstTag) 14 | { 15 | @:  16 | } 17 | isFirstTag = false; 18 | string classText = String.Format("post-tag{0}", Model.IsUserTags ? " user-tag" : string.Empty); 19 | @Html.ActionLink(tag, "Index", "Home", new {tag}, new {@class = classText, title = "show questions tagged " + tag, rel = "tag"}) 20 | } 21 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Views/Shared/_TagListVertical.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Text 2 | @model IDictionary 3 | 4 |
5 |

Recent Tags

6 | @if (Model == null || Model.Count <= 0) 7 | { 8 |

No tags

9 | } 10 | else 11 | { 12 | var tags = new StringBuilder(); 13 | foreach (string tag in Model.Keys) 14 | { 15 | tags.AppendFormat("{0}{1}{2}", tags.Length > 0 ? " " : string.Empty, "t-", tag); 16 | } 17 | 18 |
19 | @{ 20 | bool isFirstTag = true; 21 | foreach (string tag in Model.Keys) 22 | { 23 | if (!isFirstTag) 24 | { 25 |
26 | } 27 | isFirstTag = false; 28 | string title = string.Format("show questions tagged '{0}'", tag); 29 | @Html.ActionLink(tag, "Index", "Home", new {tag}, new {@class = "post-tag", title, rel = "tag"}) 30 | x @Model[tag] 31 | } 32 | } 33 | 34 |
35 | } 36 |
-------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Views/Shared/_TagSearch.cshtml: -------------------------------------------------------------------------------- 1 |  2 |
3 | 4 | 5 |
6 | 7 | 20 | 21 | @section JavaScript 22 | { 23 | 24 | } 25 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Views/Shared/_UserTagList.cshtml: -------------------------------------------------------------------------------- 1 | @using RavenOverflow.Web.Models.ViewModels 2 | @model UserTagListViewModel 3 | 4 | @if (Model == null) 5 | { 6 | return; 7 | } 8 | @{ 9 |
10 |

@Model.Header

11 |
12 | @if (Model.Tags == null || Model.Tags.Count <= 0) 13 | { 14 |

No Tags

15 | } 16 | else 17 | { 18 | Html.RenderPartial("_TagList", new TagListViewModel 19 | { 20 | IsUserTags = true, 21 | Tags = Model.Tags 22 | }); 23 | } 24 |
25 |
26 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 39 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout.cshtml"; 3 | } -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Web.Debug.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Web.Release.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 |
9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Code/RavenOverflow.Web/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | ![PewPew!](http://static.ravendb.net/badges/standard/badge1.png) 2 | 3 | ### AIM OF THIS PROJECT 4 | 5 | To help people getting started with RavenDb by showing some common problems and how to solve those problems using RavenDb as the database/persistence. 6 | 7 | ### Introduction 8 | 9 | This is a sample ASP.NET MVC3 application that leverages [RavenDB](Http://RavenDB.net) as the database / persistence store. 10 | I've copied [StackOverflow](http://stackoverflow)'s home page, include css and images. It looks a lot like it ... but I'm not a CSS/HTML Gandalf so it's a bit rough around the edges. 11 | Because I'm putting my emphasis on the how to use RavenDB .. I'm not putting much energy into the UI. If it looks similar/OK to StackOverflow, then that's enough :) 12 | 13 | Like [Racoon Blog](https://github.com/ayende/RaccoonBlog) (another sample application which is actually being used in production scenarios), this project is trying to show the benefits of RavenDb in an ASP.NET MVC3 framework. 14 | 15 | ### What it Does 16 | 17 | * List some fake questions. Summarize answers / views / tags. 18 | * Shows how to do simple queries and leverage Indexes. 19 | * Shows how to batch page queries using RavenDb 20 | 21 | ### What it Uses 22 | 23 | * [RavenDb](http://ravendb.net/) v2.0.3 (Client and Embedded) 24 | * [xUnit](http://xunit.codeplex.com/) for Tests 25 | * [ASP.NET MVC3](http://asp.net/mvc/) 26 | * [StructureMap](http://structuremap.net/structuremap/) for IoC 27 | * [NBuilder](http://nbuilder.org/) for fake data 28 | * An attempt to simulate a production solution layout (eg. n-Tier, IoC, InputModels/ViewModels) 29 | 30 | ### What it is NOT 31 | 32 | * A best practice application. I'm a noob, so this is a learning experience. 33 | 34 | ### Can I see a demo of it running? 35 | 36 | * Sure can -> http://ravenoverflow.apphb.com/ 37 | 38 | ### Support / Help 39 | 40 | * I'm usually idling on [JabbR RavenDB room](http://jabbr.net/#/rooms/RavenDB). Please drop by! :) 41 | * I accept Pull Requests, btw (hint hint) :) 42 | -------------------------------------------------------------------------------- /RavenOverflow.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{56965C84-8C59-41E3-975E-7875E2BE77BA}" 5 | ProjectSection(SolutionItems) = preProject 6 | .nuget\NuGet.exe = .nuget\NuGet.exe 7 | .nuget\NuGet.targets = .nuget\NuGet.targets 8 | EndProjectSection 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RavenOverflow.Core", "Code\RavenOverflow.Core\RavenOverflow.Core.csproj", "{58D8E77E-68D3-4623-A558-84B731E7725F}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RavenOverflow.Web", "Code\RavenOverflow.Web\RavenOverflow.Web.csproj", "{44F86C85-B711-4CF5-A161-862EE6E5D160}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RavenOverflow.FakeData", "Code\RavenOverflow.FakeData\RavenOverflow.FakeData.csproj", "{71DACF07-CC2C-4AD3-BF61-FF953DE917FF}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RavenOverflow.Services", "Code\RavenOverflow.Services\RavenOverflow.Services.csproj", "{A1F07927-5943-44D6-9FD4-FF36AE6C25DC}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RavenOverflow.Tests", "Code\RavenOverflow.Tests\RavenOverflow.Tests.csproj", "{9F1968B0-8FF6-4890-AE9E-B391447E9EA4}" 19 | EndProject 20 | Global 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug|Any CPU = Debug|Any CPU 23 | Release|Any CPU = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {58D8E77E-68D3-4623-A558-84B731E7725F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {58D8E77E-68D3-4623-A558-84B731E7725F}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {58D8E77E-68D3-4623-A558-84B731E7725F}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {58D8E77E-68D3-4623-A558-84B731E7725F}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {44F86C85-B711-4CF5-A161-862EE6E5D160}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {44F86C85-B711-4CF5-A161-862EE6E5D160}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {44F86C85-B711-4CF5-A161-862EE6E5D160}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {44F86C85-B711-4CF5-A161-862EE6E5D160}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {71DACF07-CC2C-4AD3-BF61-FF953DE917FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {71DACF07-CC2C-4AD3-BF61-FF953DE917FF}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {71DACF07-CC2C-4AD3-BF61-FF953DE917FF}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {71DACF07-CC2C-4AD3-BF61-FF953DE917FF}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {A1F07927-5943-44D6-9FD4-FF36AE6C25DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {A1F07927-5943-44D6-9FD4-FF36AE6C25DC}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {A1F07927-5943-44D6-9FD4-FF36AE6C25DC}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {A1F07927-5943-44D6-9FD4-FF36AE6C25DC}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {9F1968B0-8FF6-4890-AE9E-B391447E9EA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {9F1968B0-8FF6-4890-AE9E-B391447E9EA4}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {9F1968B0-8FF6-4890-AE9E-B391447E9EA4}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {9F1968B0-8FF6-4890-AE9E-B391447E9EA4}.Release|Any CPU.Build.0 = Release|Any CPU 46 | EndGlobalSection 47 | GlobalSection(SolutionProperties) = preSolution 48 | HideSolutionNode = FALSE 49 | EndGlobalSection 50 | EndGlobal 51 | -------------------------------------------------------------------------------- /RavenOverflow.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True 4 | DO_NOT_SHOW 5 | DO_NOT_SHOW 6 | DO_NOT_SHOW 7 | <?xml version="1.0" encoding="utf-16"?><Profile name="PK Code Cleanup"><AspOptimizeRegisterDirectives>True</AspOptimizeRegisterDirectives><HtmlReformatCode>True</HtmlReformatCode><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSRemoveCodeRedundancies>True</CSRemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSReorderTypeMembers>True</CSReorderTypeMembers><VBOptimizeImports>True</VBOptimizeImports><VBShortenReferences>True</VBShortenReferences><VBReformatCode>True</VBReformatCode><JsReformatCode>True</JsReformatCode><JsInsertSemicolon>True</JsInsertSemicolon><CssAlphabetizeProperties>True</CssAlphabetizeProperties><CssReformatCode>True</CssReformatCode><XMLReformatCode>True</XMLReformatCode></Profile> 8 | PK Code Cleanup 9 | NEXT_LINE 10 | NEXT_LINE 11 | NEXT_LINE 12 | 13 | TEMP_FOLDER 14 | TEMP_FOLDER 15 | True 16 | True 17 | True 18 | True 19 | False 20 | True 21 | 4 22 | False 23 | None 24 | False --------------------------------------------------------------------------------