diff --git a/aspclassiccompiler/NerdDinnerAsp/App_Data/ASPNETDB.MDF b/aspclassiccompiler/NerdDinnerAsp/App_Data/ASPNETDB.MDF new file mode 100644 index 0000000..7ea0dfe Binary files /dev/null and b/aspclassiccompiler/NerdDinnerAsp/App_Data/ASPNETDB.MDF differ diff --git a/aspclassiccompiler/NerdDinnerAsp/App_Data/NerdDinner.mdf b/aspclassiccompiler/NerdDinnerAsp/App_Data/NerdDinner.mdf new file mode 100644 index 0000000..f05a769 Binary files /dev/null and b/aspclassiccompiler/NerdDinnerAsp/App_Data/NerdDinner.mdf differ diff --git a/aspclassiccompiler/NerdDinnerAsp/App_Data/NerdDinner_log.ldf b/aspclassiccompiler/NerdDinnerAsp/App_Data/NerdDinner_log.ldf new file mode 100644 index 0000000..6224dd0 Binary files /dev/null and b/aspclassiccompiler/NerdDinnerAsp/App_Data/NerdDinner_log.ldf differ diff --git a/aspclassiccompiler/NerdDinnerAsp/App_Data/aspnetdb_log.ldf b/aspclassiccompiler/NerdDinnerAsp/App_Data/aspnetdb_log.ldf new file mode 100644 index 0000000..7394dba Binary files /dev/null and b/aspclassiccompiler/NerdDinnerAsp/App_Data/aspnetdb_log.ldf differ diff --git a/aspclassiccompiler/NerdDinnerAsp/ConnectionStrings.config b/aspclassiccompiler/NerdDinnerAsp/ConnectionStrings.config new file mode 100644 index 0000000..54e250a --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/ConnectionStrings.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/aspclassiccompiler/NerdDinnerAsp/Content/Site.css b/aspclassiccompiler/NerdDinnerAsp/Content/Site.css new file mode 100644 index 0000000..d5200dd --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Content/Site.css @@ -0,0 +1,378 @@ +/*---------------------------------------------------------- +The base color for this template is #5c87b2. If you'd like +to use a different color start by replacing all instances of +#5c87b2 with your new color. +----------------------------------------------------------*/ +body +{ + background-color: #5c87b2; + font-size: .75em; + font-family: Verdana, Helvetica, Sans-Serif; + margin: 0; + padding: 0; + color: #696969; +} + +a:link +{ + color: #034af3; + text-decoration: underline; +} +a:visited +{ + color: #505abc; +} +a:hover +{ + color: #1d60ff; + text-decoration: none; +} +a:active +{ + color: #12eb87; +} + +p, ul +{ + margin-bottom: 20px; + line-height: 1.6em; +} + +/* HEADINGS +----------------------------------------------------------*/ +h1, h2, h3, h4, h5, h6 +{ + font-size: 1.5em; + color: #000; + font-family: Arial, Helvetica, sans-serif; +} + +h1 +{ + font-size: 2em; + padding-bottom: 0; + margin-bottom: 0; +} +h2 +{ + padding: 0 0 10px 0; +} +h3 +{ + font-size: 1.2em; +} +h4 +{ + font-size: 1.1em; +} +h5, h6 +{ + font-size: 1em; +} + +/* this rule styles

tags that are the +first child of the left and right table columns */ +.rightColumn > h1, .rightColumn > h2, .leftColumn > h1, .leftColumn > h2 +{ + margin-top: 0; +} + +/* PRIMARY LAYOUT ELEMENTS +----------------------------------------------------------*/ + +/* you can specify a greater or lesser percentage for the +page width. Or, you can specify an exact pixel width. */ +.page +{ + width: 90%; + margin-left: auto; + margin-right: auto; +} + +#header +{ + position: relative; + margin-bottom: 0px; + color: #000; + padding: 0; +} + +#header h1 +{ + font-weight: bold; + padding: 5px 0; + margin: 0; + color: #fff; + border: none; + line-height: 2em; + font-family: Arial, Helvetica, sans-serif; + font-size: 32px !important; +} + +#main +{ + padding: 30px 30px 15px 30px; + background-color: #fff; + margin-bottom: 30px; + _height: 1px; /* only IE6 applies CSS properties starting with an underscrore */ + height: 590px; +} + +#footer +{ + color: #999; + padding: 10px 0; + text-align: center; + line-height: normal; + margin: 0; + font-size: .9em; +} + +/* TAB MENU +----------------------------------------------------------*/ +ul#menu +{ + border-bottom: 1px #5C87B2 solid; + padding: 0 0 2px; + position: relative; + margin: 0; + text-align: right; +} + +ul#menu li +{ + display: inline; + list-style: none; +} + +ul#menu li#greeting +{ + padding: 10px 20px; + font-weight: bold; + text-decoration: none; + line-height: 2.8em; + color: #fff; +} + +ul#menu li a +{ + padding: 10px 20px; + font-weight: bold; + text-decoration: none; + line-height: 2.8em; + background-color: #e8eef4; + color: #034af3; +} + +ul#menu li a:hover +{ + background-color: #fff; + text-decoration: none; +} + +ul#menu li a:active +{ + background-color: #a6e2a6; + text-decoration: none; +} + +ul#menu li.selected a +{ + background-color: #fff; + color: #000; +} + +/* FORM LAYOUT ELEMENTS +----------------------------------------------------------*/ + +fieldset +{ + margin: 1em 0; + padding: 1em; + border: 1px solid #CCC; +} + +fieldset p +{ + margin: 2px 12px 10px 10px; +} + +fieldset label +{ + display: block; +} + +fieldset label.inline +{ + display: inline; +} + +legend +{ + font-size: 1.1em; + font-weight: 600; + padding: 2px 4px 8px 4px; +} + +input[type="text"] +{ + width: 200px; + border: 1px solid #CCC; +} + +input[type="password"] +{ + width: 200px; + border: 1px solid #CCC; +} + +/* TABLE +----------------------------------------------------------*/ + +table +{ + border: solid 1px #e8eef4; + border-collapse: collapse; +} + +table td +{ + padding: 5px; + border: solid 1px #e8eef4; +} + +table th +{ + padding: 6px 5px; + text-align: left; + background-color: #e8eef4; + border: solid 1px #e8eef4; +} + +/* MISC +----------------------------------------------------------*/ +.clear +{ + clear: both; +} + +.error +{ + color:Red; +} + +#menucontainer +{ + margin-top:40px; +} + +div#title +{ + display:block; + float:left; + text-align:left; +} + +#logindisplay +{ + font-size:1.1em; + display:block; + text-align:right; + margin:10px; + color:White; +} + +#logindisplay a:link +{ + color: white; + text-decoration: underline; +} + +#logindisplay a:visited +{ + color: white; + text-decoration: underline; +} + +#logindisplay a:hover +{ + color: white; + text-decoration: none; +} + +.field-validation-error +{ + color: #ff0000; +} + +.input-validation-error +{ + border: 1px solid #ff0000; + background-color: #ffeeee; +} + +.validation-summary-errors +{ + font-weight: bold; + color: #ff0000; +} + +#dinnerform textarea +{ + width:200px; + height:70px; +} + +#dinnerDiv textarea +{ + width:200px; + height:70px; +} + +#rsvpmsg +{ + color:Red; +} + +hr +{ + padding:0px, 10px, 0px, 10px; + height:1px; +} + +#pagination +{ + text-align:center; +} + +#dinnerDiv { + float: left; + width: 280px; +} + +#mapDiv { + float: left; +} + +#mapDivLeft { + float: left; +} + +#mapDivRight { + padding: 30px 0px 0px 20px; + float: left; +} + +#dinnerList { + padding:0px 0px 0px 0px; +} + +#searchBox { + padding:0px 0px 10px 0px; +} + +#theMap { + position: relative; + width: 500px; + height: 450px; +} \ No newline at end of file diff --git a/aspclassiccompiler/NerdDinnerAsp/Content/nerd.jpg b/aspclassiccompiler/NerdDinnerAsp/Content/nerd.jpg new file mode 100644 index 0000000..f60b5b4 Binary files /dev/null and b/aspclassiccompiler/NerdDinnerAsp/Content/nerd.jpg differ diff --git a/aspclassiccompiler/NerdDinnerAsp/Controllers/AccountController.cs b/aspclassiccompiler/NerdDinnerAsp/Controllers/AccountController.cs new file mode 100644 index 0000000..8ce6d77 --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Controllers/AccountController.cs @@ -0,0 +1,297 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Security.Principal; +using System.Web; +using System.Web.Mvc; +using System.Web.Security; +using System.Web.UI; + +namespace NerdDinner.Controllers { + + [HandleError] + public class AccountController : Controller { + + // This constructor is used by the MVC framework to instantiate the controller using + // the default forms authentication and membership providers. + + public AccountController() + : this(null, null) { + } + + // This constructor is not used by the MVC framework but is instead provided for ease + // of unit testing this type. See the comments at the end of this file for more + // information. + public AccountController(IFormsAuthentication formsAuth, IMembershipService service) { + FormsAuth = formsAuth ?? new FormsAuthenticationService(); + MembershipService = service ?? new AccountMembershipService(); + } + + public IFormsAuthentication FormsAuth { + get; + private set; + } + + public IMembershipService MembershipService { + get; + private set; + } + + public ActionResult LogOn() { + + return View(); + } + + [AcceptVerbs(HttpVerbs.Post)] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", + Justification = "Needs to take same parameter type as Controller.Redirect()")] + public ActionResult LogOn(string userName, string password, bool rememberMe, string returnUrl) { + + if (!ValidateLogOn(userName, password)) { + ViewData["rememberMe"] = rememberMe; + return View(); + } + + FormsAuth.SignIn(userName, rememberMe); + if (!String.IsNullOrEmpty(returnUrl)) { + return Redirect(returnUrl); + } + else { + return RedirectToAction("Index", "Home"); + } + } + + public ActionResult LogOff() { + + FormsAuth.SignOut(); + + return RedirectToAction("Index", "Home"); + } + + public ActionResult Register() { + + ViewData["PasswordLength"] = MembershipService.MinPasswordLength; + + return View(); + } + + [AcceptVerbs(HttpVerbs.Post)] + public ActionResult Register(string userName, string email, string password, string confirmPassword) { + + ViewData["PasswordLength"] = MembershipService.MinPasswordLength; + + if (ValidateRegistration(userName, email, password, confirmPassword)) { + // Attempt to register the user + MembershipCreateStatus createStatus = MembershipService.CreateUser(userName, password, email); + + if (createStatus == MembershipCreateStatus.Success) { + FormsAuth.SignIn(userName, false /* createPersistentCookie */); + return RedirectToAction("Index", "Home"); + } + else { + ModelState.AddModelError("_FORM", ErrorCodeToString(createStatus)); + } + } + + // If we got this far, something failed, redisplay form + return View(); + } + + [Authorize] + public ActionResult ChangePassword() { + + ViewData["PasswordLength"] = MembershipService.MinPasswordLength; + + return View(); + } + + [Authorize] + [AcceptVerbs(HttpVerbs.Post)] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", + Justification = "Exceptions result in password not being changed.")] + public ActionResult ChangePassword(string currentPassword, string newPassword, string confirmPassword) { + + ViewData["PasswordLength"] = MembershipService.MinPasswordLength; + + if (!ValidateChangePassword(currentPassword, newPassword, confirmPassword)) { + return View(); + } + + try { + if (MembershipService.ChangePassword(User.Identity.Name, currentPassword, newPassword)) { + return RedirectToAction("ChangePasswordSuccess"); + } + else { + ModelState.AddModelError("_FORM", "The current password is incorrect or the new password is invalid."); + return View(); + } + } + catch { + ModelState.AddModelError("_FORM", "The current password is incorrect or the new password is invalid."); + return View(); + } + } + + public ActionResult ChangePasswordSuccess() { + + return View(); + } + + protected override void OnActionExecuting(ActionExecutingContext filterContext) { + if (filterContext.HttpContext.User.Identity is WindowsIdentity) { + throw new InvalidOperationException("Windows authentication is not supported."); + } + } + + #region Validation Methods + + private bool ValidateChangePassword(string currentPassword, string newPassword, string confirmPassword) { + if (String.IsNullOrEmpty(currentPassword)) { + ModelState.AddModelError("currentPassword", "You must specify a current password."); + } + if (newPassword == null || newPassword.Length < MembershipService.MinPasswordLength) { + ModelState.AddModelError("newPassword", + String.Format(CultureInfo.CurrentCulture, + "You must specify a new password of {0} or more characters.", + MembershipService.MinPasswordLength)); + } + + if (!String.Equals(newPassword, confirmPassword, StringComparison.Ordinal)) { + ModelState.AddModelError("_FORM", "The new password and confirmation password do not match."); + } + + return ModelState.IsValid; + } + + private bool ValidateLogOn(string userName, string password) { + if (String.IsNullOrEmpty(userName)) { + ModelState.AddModelError("username", "You must specify a username."); + } + if (String.IsNullOrEmpty(password)) { + ModelState.AddModelError("password", "You must specify a password."); + } + if (!MembershipService.ValidateUser(userName, password)) { + ModelState.AddModelError("_FORM", "The username or password provided is incorrect."); + } + + return ModelState.IsValid; + } + + private bool ValidateRegistration(string userName, string email, string password, string confirmPassword) { + if (String.IsNullOrEmpty(userName)) { + ModelState.AddModelError("username", "You must specify a username."); + } + if (String.IsNullOrEmpty(email)) { + ModelState.AddModelError("email", "You must specify an email address."); + } + if (password == null || password.Length < MembershipService.MinPasswordLength) { + ModelState.AddModelError("password", + String.Format(CultureInfo.CurrentCulture, + "You must specify a password of {0} or more characters.", + MembershipService.MinPasswordLength)); + } + if (!String.Equals(password, confirmPassword, StringComparison.Ordinal)) { + ModelState.AddModelError("_FORM", "The new password and confirmation password do not match."); + } + return ModelState.IsValid; + } + + private static string ErrorCodeToString(MembershipCreateStatus createStatus) { + // See http://msdn.microsoft.com/en-us/library/system.web.security.membershipcreatestatus.aspx for + // a full list of status codes. + switch (createStatus) { + case MembershipCreateStatus.DuplicateUserName: + return "Username already exists. Please enter a different user name."; + + case MembershipCreateStatus.DuplicateEmail: + return "A username for that e-mail address already exists. Please enter a different e-mail address."; + + case MembershipCreateStatus.InvalidPassword: + return "The password provided is invalid. Please enter a valid password value."; + + case MembershipCreateStatus.InvalidEmail: + return "The e-mail address provided is invalid. Please check the value and try again."; + + case MembershipCreateStatus.InvalidAnswer: + return "The password retrieval answer provided is invalid. Please check the value and try again."; + + case MembershipCreateStatus.InvalidQuestion: + return "The password retrieval question provided is invalid. Please check the value and try again."; + + case MembershipCreateStatus.InvalidUserName: + return "The user name provided is invalid. Please check the value and try again."; + + case MembershipCreateStatus.ProviderError: + return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator."; + + case MembershipCreateStatus.UserRejected: + return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator."; + + default: + return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator."; + } + } + #endregion + } + + // The FormsAuthentication type is sealed and contains static members, so it is difficult to + // unit test code that calls its members. The interface and helper class below demonstrate + // how to create an abstract wrapper around such a type in order to make the AccountController + // code unit testable. + + public interface IFormsAuthentication { + void SignIn(string userName, bool createPersistentCookie); + void SignOut(); + } + + public class FormsAuthenticationService : IFormsAuthentication { + public void SignIn(string userName, bool createPersistentCookie) { + FormsAuthentication.SetAuthCookie(userName, createPersistentCookie); + } + public void SignOut() { + FormsAuthentication.SignOut(); + } + } + + public interface IMembershipService { + int MinPasswordLength { get; } + + bool ValidateUser(string userName, string password); + MembershipCreateStatus CreateUser(string userName, string password, string email); + bool ChangePassword(string userName, string oldPassword, string newPassword); + } + + public class AccountMembershipService : IMembershipService { + private MembershipProvider _provider; + + public AccountMembershipService() + : this(null) { + } + + public AccountMembershipService(MembershipProvider provider) { + _provider = provider ?? Membership.Provider; + } + + public int MinPasswordLength { + get { + return _provider.MinRequiredPasswordLength; + } + } + + public bool ValidateUser(string userName, string password) { + return _provider.ValidateUser(userName, password); + } + + public MembershipCreateStatus CreateUser(string userName, string password, string email) { + MembershipCreateStatus status; + _provider.CreateUser(userName, password, email, null, null, true, null, out status); + return status; + } + + public bool ChangePassword(string userName, string oldPassword, string newPassword) { + MembershipUser currentUser = _provider.GetUser(userName, true /* userIsOnline */); + return currentUser.ChangePassword(oldPassword, newPassword); + } + } +} diff --git a/aspclassiccompiler/NerdDinnerAsp/Controllers/DinnersController.cs b/aspclassiccompiler/NerdDinnerAsp/Controllers/DinnersController.cs new file mode 100644 index 0000000..95306e7 --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Controllers/DinnersController.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web.Mvc; +using NerdDinner.Helpers; +using NerdDinner.Models; + +namespace NerdDinner.Controllers { + + // + // ViewModel Classes + + public class DinnerFormViewModel { + + // Properties + public Dinner Dinner { get; private set; } + public SelectList Countries { get; private set; } + + // Constructor + public DinnerFormViewModel(Dinner dinner) { + Dinner = dinner; + Countries = new SelectList(PhoneValidator.Countries, Dinner.Country); + } + } + + // + // Controller Class + + [HandleError] + public class DinnersController : Controller { + + IDinnerRepository dinnerRepository; + + // + // Dependency Injection enabled constructors + + public DinnersController() + : this(new DinnerRepository()) { + } + + public DinnersController(IDinnerRepository repository) { + dinnerRepository = repository; + } + + // + // GET: /Dinners/ + // /Dinners/Page/2 + + public ActionResult Index(int? page) { + + const int pageSize = 10; + + var upcomingDinners = dinnerRepository.FindUpcomingDinners(); + var paginatedDinners = new PaginatedList(upcomingDinners, page ?? 0, pageSize); + + return View(paginatedDinners); + } + + // + // GET: /Dinners/Details/5 + + public ActionResult Details(int id) { + + Dinner dinner = dinnerRepository.GetDinner(id); + + if (dinner == null) + return View("NotFound"); + + return View(dinner); + } + + // + // GET: /Dinners/Edit/5 + + [Authorize] + public ActionResult Edit(int id) { + + Dinner dinner = dinnerRepository.GetDinner(id); + + if (!dinner.IsHostedBy(User.Identity.Name)) + return View("InvalidOwner"); + + return View(new DinnerFormViewModel(dinner)); + } + + // + // POST: /Dinners/Edit/5 + + [AcceptVerbs(HttpVerbs.Post), Authorize] + public ActionResult Edit(int id, FormCollection collection) { + + Dinner dinner = dinnerRepository.GetDinner(id); + + if (!dinner.IsHostedBy(User.Identity.Name)) + return View("InvalidOwner"); + + try { + UpdateModel(dinner); + + dinnerRepository.Save(); + + return RedirectToAction("Details", new { id=dinner.DinnerID }); + } + catch { + ModelState.AddModelErrors(dinner.GetRuleViolations()); + + return View(new DinnerFormViewModel(dinner)); + } + } + + // + // GET: /Dinners/Create + + [Authorize] + public ActionResult Create() { + + Dinner dinner = new Dinner() { + EventDate = DateTime.Now.AddDays(7) + }; + + return View(new DinnerFormViewModel(dinner)); + } + + // + // POST: /Dinners/Create + + [AcceptVerbs(HttpVerbs.Post), Authorize] + public ActionResult Create(Dinner dinner) { + + if (ModelState.IsValid) { + + try { + dinner.HostedBy = User.Identity.Name; + + RSVP rsvp = new RSVP(); + rsvp.AttendeeName = User.Identity.Name; + dinner.RSVPs.Add(rsvp); + + dinnerRepository.Add(dinner); + dinnerRepository.Save(); + + return RedirectToAction("Details", new { id=dinner.DinnerID }); + } + catch { + ModelState.AddModelErrors(dinner.GetRuleViolations()); + } + } + + return View(new DinnerFormViewModel(dinner)); + } + + // + // HTTP GET: /Dinners/Delete/1 + + [Authorize] + public ActionResult Delete(int id) { + + Dinner dinner = dinnerRepository.GetDinner(id); + + if (dinner == null) + return View("NotFound"); + + if (!dinner.IsHostedBy(User.Identity.Name)) + return View("InvalidOwner"); + + return View(dinner); + } + + // + // HTTP POST: /Dinners/Delete/1 + + [AcceptVerbs(HttpVerbs.Post), Authorize] + public ActionResult Delete(int id, string confirmButton) { + + Dinner dinner = dinnerRepository.GetDinner(id); + + if (dinner == null) + return View("NotFound"); + + if (!dinner.IsHostedBy(User.Identity.Name)) + return View("InvalidOwner"); + + dinnerRepository.Delete(dinner); + dinnerRepository.Save(); + + return View("Deleted"); + } + } +} diff --git a/aspclassiccompiler/NerdDinnerAsp/Controllers/HomeController.cs b/aspclassiccompiler/NerdDinnerAsp/Controllers/HomeController.cs new file mode 100644 index 0000000..b0105a7 --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Controllers/HomeController.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; + +namespace NerdDinner.Controllers { + + [HandleError] + public class HomeController : Controller { + + public ActionResult Index() { + return View(); + } + + public ActionResult About() { + return View(); + } + } +} diff --git a/aspclassiccompiler/NerdDinnerAsp/Controllers/RSVPController.cs b/aspclassiccompiler/NerdDinnerAsp/Controllers/RSVPController.cs new file mode 100644 index 0000000..1c01d4f --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Controllers/RSVPController.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using NerdDinner.Models; + +namespace NerdDinner.Controllers +{ + public class RSVPController : Controller { + + IDinnerRepository dinnerRepository; + + // + // Dependency Injection enabled constructors + + public RSVPController() + : this(new DinnerRepository()) { + } + + public RSVPController(IDinnerRepository repository) { + dinnerRepository = repository; + } + + // + // AJAX: /Dinners/Register/1 + + [Authorize, AcceptVerbs(HttpVerbs.Post)] + public ActionResult Register(int id) { + + Dinner dinner = dinnerRepository.GetDinner(id); + + if (!dinner.IsUserRegistered(User.Identity.Name)) { + + RSVP rsvp = new RSVP(); + rsvp.AttendeeName = User.Identity.Name; + + dinner.RSVPs.Add(rsvp); + dinnerRepository.Save(); + } + + return Content("Thanks - we'll see you there!"); + } + } +} diff --git a/aspclassiccompiler/NerdDinnerAsp/Controllers/SearchController.cs b/aspclassiccompiler/NerdDinnerAsp/Controllers/SearchController.cs new file mode 100644 index 0000000..0431aa2 --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Controllers/SearchController.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using NerdDinner.Models; + +namespace NerdDinner.Controllers { + + public class JsonDinner { + public int DinnerID { get; set; } + public string Title { get; set; } + public double Latitude { get; set; } + public double Longitude { get; set; } + public string Description { get; set; } + public int RSVPCount { get; set; } + } + + public class SearchController : Controller { + + IDinnerRepository dinnerRepository; + + // + // Dependency Injection enabled constructors + + public SearchController() + : this(new DinnerRepository()) { + } + + public SearchController(IDinnerRepository repository) { + dinnerRepository = repository; + } + + // + // AJAX: /Search/FindByLocation?longitude=45&latitude=-90 + + [AcceptVerbs(HttpVerbs.Post)] + public ActionResult SearchByLocation(float latitude, float longitude) { + + var dinners = dinnerRepository.FindByLocation(latitude, longitude); + + var jsonDinners = from dinner in dinners + select new JsonDinner { + DinnerID = dinner.DinnerID, + Latitude = dinner.Latitude, + Longitude = dinner.Longitude, + Title = dinner.Title, + Description = dinner.Description, + RSVPCount = dinner.RSVPs.Count + }; + + return Json(jsonDinners.ToList()); + } + } +} diff --git a/aspclassiccompiler/NerdDinnerAsp/Default.aspx b/aspclassiccompiler/NerdDinnerAsp/Default.aspx new file mode 100644 index 0000000..8f297a6 --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Default.aspx @@ -0,0 +1,3 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="NerdDinner._Default" %> + +<%-- Please do not delete this file. It is used to ensure that ASP.NET MVC is activated by IIS when a user makes a "/" request to the server. --%> diff --git a/aspclassiccompiler/NerdDinnerAsp/Default.aspx.cs b/aspclassiccompiler/NerdDinnerAsp/Default.aspx.cs new file mode 100644 index 0000000..24e1def --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Default.aspx.cs @@ -0,0 +1,13 @@ +using System.Web; +using System.Web.Mvc; +using System.Web.UI; + +namespace NerdDinner { + public partial class _Default : Page { + public void Page_Load(object sender, System.EventArgs e) { + HttpContext.Current.RewritePath(Request.ApplicationPath, false); + IHttpHandler httpHandler = new MvcHttpHandler(); + httpHandler.ProcessRequest(HttpContext.Current); + } + } +} diff --git a/aspclassiccompiler/NerdDinnerAsp/Global.asax b/aspclassiccompiler/NerdDinnerAsp/Global.asax new file mode 100644 index 0000000..be524c6 --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Global.asax @@ -0,0 +1 @@ +<%@ Application Codebehind="Global.asax.cs" Inherits="NerdDinner.MvcApplication" Language="C#" %> diff --git a/aspclassiccompiler/NerdDinnerAsp/Global.asax.cs b/aspclassiccompiler/NerdDinnerAsp/Global.asax.cs new file mode 100644 index 0000000..2d620c4 --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Global.asax.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; +using Dlrsoft.Asp.Mvc; + +namespace NerdDinner { + + public class MvcApplication : System.Web.HttpApplication { + + public void RegisterRoutes(RouteCollection routes) { + + routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); + + routes.MapRoute( + "UpcomingDinners", + "Dinners/Page/{page}", + new { controller = "Dinners", action = "Index" } + ); + + routes.MapRoute( + "Default", // Route name + "{controller}/{action}/{id}", // URL with parameters + new { controller = "Home", action = "Index", id = "" } // Parameter defaults + ); + } + + void Application_Start() { + RegisterRoutes(RouteTable.Routes); + ViewEngines.Engines.Clear(); + ViewEngines.Engines.Add(new AspViewEngine()); + ViewEngines.Engines.Add(new WebFormViewEngine()); + } + } +} \ No newline at end of file diff --git a/aspclassiccompiler/NerdDinnerAsp/Helpers/ControllerHelpers.cs b/aspclassiccompiler/NerdDinnerAsp/Helpers/ControllerHelpers.cs new file mode 100644 index 0000000..080a00e --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Helpers/ControllerHelpers.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using NerdDinner.Models; +using System.Web.Mvc; + +namespace NerdDinner.Helpers { + + public static class ModelStateHelpers { + + public static void AddModelErrors(this ModelStateDictionary modelState, IEnumerable errors) { + + foreach (RuleViolation issue in errors) { + modelState.AddModelError(issue.PropertyName, issue.ErrorMessage); + } + } + } +} diff --git a/aspclassiccompiler/NerdDinnerAsp/Helpers/PaginatedList.cs b/aspclassiccompiler/NerdDinnerAsp/Helpers/PaginatedList.cs new file mode 100644 index 0000000..b0d4ddc --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Helpers/PaginatedList.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace NerdDinner.Helpers { + + public class PaginatedList : List { + + public int PageIndex { get; private set; } + public int PageSize { get; private set; } + public int TotalCount { get; private set; } + public int TotalPages { get; private set; } + + public PaginatedList(IQueryable source, int pageIndex, int pageSize) { + PageIndex = pageIndex; + PageSize = pageSize; + TotalCount = source.Count(); + TotalPages = (int) Math.Ceiling(TotalCount / (double)PageSize); + + this.AddRange(source.Skip(PageIndex * PageSize).Take(PageSize)); + } + + public bool HasPreviousPage { + get { + return (PageIndex > 0); + } + } + + public bool HasNextPage { + get { + return (PageIndex+1 < TotalPages); + } + } + } +} diff --git a/aspclassiccompiler/NerdDinnerAsp/Helpers/PhoneValidator.cs b/aspclassiccompiler/NerdDinnerAsp/Helpers/PhoneValidator.cs new file mode 100644 index 0000000..e7500d1 --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Helpers/PhoneValidator.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Text.RegularExpressions; + +namespace NerdDinner.Helpers { + + public class PhoneValidator { + + static IDictionary countryRegex = new Dictionary() + { + { "USA", new Regex("^[2-9]\\d{2}-\\d{3}-\\d{4}$")}, + { "UK", new Regex("(^1300\\d{6}$)|(^1800|1900|1902\\d{6}$)|(^0[2|3|7|8]{1}[0-9]{8}$)|(^13\\d{4}$)|(^04\\d{2,3}\\d{6}$)")}, + { "Netherlands", new Regex("(^\\+[0-9]{2}|^\\+[0-9]{2}\\(0\\)|^\\(\\+[0-9]{2}\\)\\(0\\)|^00[0-9]{2}|^0)([0-9]{9}$|[0-9\\-\\s]{10}$)")}, + }; + + public static bool IsValidNumber(string phoneNumber, string country) { + + if (country != null && countryRegex.ContainsKey(country)) + return countryRegex[country].IsMatch(phoneNumber); + else + return false; + } + + public static IEnumerable Countries { + get { + return countryRegex.Keys; + } + } + } +} diff --git a/aspclassiccompiler/NerdDinnerAsp/Models/Dinner.cs b/aspclassiccompiler/NerdDinnerAsp/Models/Dinner.cs new file mode 100644 index 0000000..53bf556 --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Models/Dinner.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Data.Linq; +using System.Web.Mvc; +using NerdDinner.Helpers; + +namespace NerdDinner.Models { + + [Bind(Include="Title,Description,EventDate,Address,Country,ContactPhone,Latitude,Longitude")] + public partial class Dinner { + + public bool IsHostedBy(string userName) { + return HostedBy.Equals(userName, StringComparison.InvariantCultureIgnoreCase); + } + + public bool IsUserRegistered(string userName) { + return RSVPs.Any(r => r.AttendeeName.Equals(userName, StringComparison.InvariantCultureIgnoreCase)); + } + + public bool IsValid { + get { return (GetRuleViolations().Count() == 0); } + } + + public IEnumerable GetRuleViolations() { + + if (String.IsNullOrEmpty(Title)) + yield return new RuleViolation("Title is required", "Title"); + + if (String.IsNullOrEmpty(Description)) + yield return new RuleViolation("Description is required", "Description"); + + if (String.IsNullOrEmpty(HostedBy)) + yield return new RuleViolation("HostedBy is required", "HostedBy"); + + if (String.IsNullOrEmpty(Address)) + yield return new RuleViolation("Address is required", "Address"); + + if (String.IsNullOrEmpty(Country)) + yield return new RuleViolation("Country is required", "Address"); + + if (String.IsNullOrEmpty(ContactPhone)) + yield return new RuleViolation("Phone# is required", "ContactPhone"); + + if (!PhoneValidator.IsValidNumber(ContactPhone, Country)) + yield return new RuleViolation("Phone# does not match country", "ContactPhone"); + + yield break; + } + + partial void OnValidate(ChangeAction action) { + if (!IsValid) + throw new ApplicationException("Rule violations prevent saving"); + } + } +} diff --git a/aspclassiccompiler/NerdDinnerAsp/Models/DinnerRepository.cs b/aspclassiccompiler/NerdDinnerAsp/Models/DinnerRepository.cs new file mode 100644 index 0000000..7919793 --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Models/DinnerRepository.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace NerdDinner.Models { + + public class DinnerRepository : NerdDinner.Models.IDinnerRepository { + + NerdDinnerDataContext db = new NerdDinnerDataContext(); + + // + // Query Methods + + public IQueryable FindAllDinners() { + return db.Dinners; + } + + public IQueryable FindUpcomingDinners() { + return from dinner in FindAllDinners() + where dinner.EventDate > DateTime.Now + orderby dinner.EventDate + select dinner; + } + + public IQueryable FindByLocation(float latitude, float longitude) { + var dinners = from dinner in FindUpcomingDinners() + join i in db.NearestDinners(latitude, longitude) + on dinner.DinnerID equals i.DinnerID + select dinner; + + return dinners; + } + + public Dinner GetDinner(int id) { + return db.Dinners.SingleOrDefault(d => d.DinnerID == id); + } + + // + // Insert/Delete Methods + + public void Add(Dinner dinner) { + db.Dinners.InsertOnSubmit(dinner); + } + + public void Delete(Dinner dinner) { + db.RSVPs.DeleteAllOnSubmit(dinner.RSVPs); + db.Dinners.DeleteOnSubmit(dinner); + } + + // + // Persistence + + public void Save() { + db.SubmitChanges(); + } + } +} diff --git a/aspclassiccompiler/NerdDinnerAsp/Models/IDinnerRepository.cs b/aspclassiccompiler/NerdDinnerAsp/Models/IDinnerRepository.cs new file mode 100644 index 0000000..9e32d98 --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Models/IDinnerRepository.cs @@ -0,0 +1,18 @@ +using System; +using System.Linq; + +namespace NerdDinner.Models { + + public interface IDinnerRepository { + + IQueryable FindAllDinners(); + IQueryable FindByLocation(float latitude, float longitude); + IQueryable FindUpcomingDinners(); + Dinner GetDinner(int id); + + void Add(Dinner dinner); + void Delete(Dinner dinner); + + void Save(); + } +} diff --git a/aspclassiccompiler/NerdDinnerAsp/Models/NerdDinner.dbml b/aspclassiccompiler/NerdDinnerAsp/Models/NerdDinner.dbml new file mode 100644 index 0000000..7912d94 --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Models/NerdDinner.dbml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/aspclassiccompiler/NerdDinnerAsp/Models/NerdDinner.dbml.layout b/aspclassiccompiler/NerdDinnerAsp/Models/NerdDinner.dbml.layout new file mode 100644 index 0000000..eba0715 --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Models/NerdDinner.dbml.layout @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aspclassiccompiler/NerdDinnerAsp/Models/NerdDinner.designer.cs b/aspclassiccompiler/NerdDinnerAsp/Models/NerdDinner.designer.cs new file mode 100644 index 0000000..feaa57a --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Models/NerdDinner.designer.cs @@ -0,0 +1,583 @@ +#pragma warning disable 1591 +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.3521 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace NerdDinner.Models +{ + using System.Data.Linq; + using System.Data.Linq.Mapping; + using System.Data; + using System.Collections.Generic; + using System.Reflection; + using System.Linq; + using System.Linq.Expressions; + using System.ComponentModel; + using System; + + + [System.Data.Linq.Mapping.DatabaseAttribute(Name="NerdDinner")] + public partial class NerdDinnerDataContext : System.Data.Linq.DataContext + { + + private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource(); + + #region Extensibility Method Definitions + partial void OnCreated(); + partial void InsertDinner(Dinner instance); + partial void UpdateDinner(Dinner instance); + partial void DeleteDinner(Dinner instance); + partial void InsertRSVP(RSVP instance); + partial void UpdateRSVP(RSVP instance); + partial void DeleteRSVP(RSVP instance); + #endregion + + public NerdDinnerDataContext() : + base(global::System.Configuration.ConfigurationManager.ConnectionStrings["NerdDinnerConnectionString"].ConnectionString, mappingSource) + { + OnCreated(); + } + + public NerdDinnerDataContext(string connection) : + base(connection, mappingSource) + { + OnCreated(); + } + + public NerdDinnerDataContext(System.Data.IDbConnection connection) : + base(connection, mappingSource) + { + OnCreated(); + } + + public NerdDinnerDataContext(string connection, System.Data.Linq.Mapping.MappingSource mappingSource) : + base(connection, mappingSource) + { + OnCreated(); + } + + public NerdDinnerDataContext(System.Data.IDbConnection connection, System.Data.Linq.Mapping.MappingSource mappingSource) : + base(connection, mappingSource) + { + OnCreated(); + } + + public System.Data.Linq.Table Dinners + { + get + { + return this.GetTable(); + } + } + + public System.Data.Linq.Table RSVPs + { + get + { + return this.GetTable(); + } + } + + [Function(Name="dbo.NearestDinners", IsComposable=true)] + public IQueryable NearestDinners([Parameter(DbType="Real")] System.Nullable lat, [Parameter(Name="long", DbType="Real")] System.Nullable @long) + { + return this.CreateMethodCallQuery(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), lat, @long); + } + + [Function(Name="dbo.DistanceBetween", IsComposable=true)] + public System.Nullable DistanceBetween([Parameter(Name="Lat1", DbType="Real")] System.Nullable lat1, [Parameter(Name="Long1", DbType="Real")] System.Nullable long1, [Parameter(Name="Lat2", DbType="Real")] System.Nullable lat2, [Parameter(Name="Long2", DbType="Real")] System.Nullable long2) + { + return ((System.Nullable)(this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), lat1, long1, lat2, long2).ReturnValue)); + } + } + + [Table(Name="dbo.Dinners")] + public partial class Dinner : INotifyPropertyChanging, INotifyPropertyChanged + { + + private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty); + + private int _DinnerID; + + private string _Title; + + private System.DateTime _EventDate; + + private string _Description; + + private string _HostedBy; + + private string _ContactPhone; + + private string _Address; + + private string _Country; + + private double _Latitude; + + private double _Longitude; + + private EntitySet _RSVPs; + + #region Extensibility Method Definitions + partial void OnLoaded(); + partial void OnValidate(System.Data.Linq.ChangeAction action); + partial void OnCreated(); + partial void OnDinnerIDChanging(int value); + partial void OnDinnerIDChanged(); + partial void OnTitleChanging(string value); + partial void OnTitleChanged(); + partial void OnEventDateChanging(System.DateTime value); + partial void OnEventDateChanged(); + partial void OnDescriptionChanging(string value); + partial void OnDescriptionChanged(); + partial void OnHostedByChanging(string value); + partial void OnHostedByChanged(); + partial void OnContactPhoneChanging(string value); + partial void OnContactPhoneChanged(); + partial void OnAddressChanging(string value); + partial void OnAddressChanged(); + partial void OnCountryChanging(string value); + partial void OnCountryChanged(); + partial void OnLatitudeChanging(double value); + partial void OnLatitudeChanged(); + partial void OnLongitudeChanging(double value); + partial void OnLongitudeChanged(); + #endregion + + public Dinner() + { + this._RSVPs = new EntitySet(new Action(this.attach_RSVPs), new Action(this.detach_RSVPs)); + OnCreated(); + } + + [Column(Storage="_DinnerID", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)] + public int DinnerID + { + get + { + return this._DinnerID; + } + set + { + if ((this._DinnerID != value)) + { + this.OnDinnerIDChanging(value); + this.SendPropertyChanging(); + this._DinnerID = value; + this.SendPropertyChanged("DinnerID"); + this.OnDinnerIDChanged(); + } + } + } + + [Column(Storage="_Title", DbType="NVarChar(50) NOT NULL", CanBeNull=false)] + public string Title + { + get + { + return this._Title; + } + set + { + if ((this._Title != value)) + { + this.OnTitleChanging(value); + this.SendPropertyChanging(); + this._Title = value; + this.SendPropertyChanged("Title"); + this.OnTitleChanged(); + } + } + } + + [Column(Storage="_EventDate", DbType="DateTime NOT NULL")] + public System.DateTime EventDate + { + get + { + return this._EventDate; + } + set + { + if ((this._EventDate != value)) + { + this.OnEventDateChanging(value); + this.SendPropertyChanging(); + this._EventDate = value; + this.SendPropertyChanged("EventDate"); + this.OnEventDateChanged(); + } + } + } + + [Column(Storage="_Description", DbType="NVarChar(256)")] + public string Description + { + get + { + return this._Description; + } + set + { + if ((this._Description != value)) + { + this.OnDescriptionChanging(value); + this.SendPropertyChanging(); + this._Description = value; + this.SendPropertyChanged("Description"); + this.OnDescriptionChanged(); + } + } + } + + [Column(Storage="_HostedBy", DbType="NVarChar(50) NOT NULL", CanBeNull=false)] + public string HostedBy + { + get + { + return this._HostedBy; + } + set + { + if ((this._HostedBy != value)) + { + this.OnHostedByChanging(value); + this.SendPropertyChanging(); + this._HostedBy = value; + this.SendPropertyChanged("HostedBy"); + this.OnHostedByChanged(); + } + } + } + + [Column(Storage="_ContactPhone", DbType="NVarChar(50) NOT NULL", CanBeNull=false)] + public string ContactPhone + { + get + { + return this._ContactPhone; + } + set + { + if ((this._ContactPhone != value)) + { + this.OnContactPhoneChanging(value); + this.SendPropertyChanging(); + this._ContactPhone = value; + this.SendPropertyChanged("ContactPhone"); + this.OnContactPhoneChanged(); + } + } + } + + [Column(Storage="_Address", DbType="NVarChar(50)")] + public string Address + { + get + { + return this._Address; + } + set + { + if ((this._Address != value)) + { + this.OnAddressChanging(value); + this.SendPropertyChanging(); + this._Address = value; + this.SendPropertyChanged("Address"); + this.OnAddressChanged(); + } + } + } + + [Column(Storage="_Country", DbType="NVarChar(30)")] + public string Country + { + get + { + return this._Country; + } + set + { + if ((this._Country != value)) + { + this.OnCountryChanging(value); + this.SendPropertyChanging(); + this._Country = value; + this.SendPropertyChanged("Country"); + this.OnCountryChanged(); + } + } + } + + [Column(Storage="_Latitude", DbType="Float NOT NULL")] + public double Latitude + { + get + { + return this._Latitude; + } + set + { + if ((this._Latitude != value)) + { + this.OnLatitudeChanging(value); + this.SendPropertyChanging(); + this._Latitude = value; + this.SendPropertyChanged("Latitude"); + this.OnLatitudeChanged(); + } + } + } + + [Column(Storage="_Longitude", DbType="Float NOT NULL")] + public double Longitude + { + get + { + return this._Longitude; + } + set + { + if ((this._Longitude != value)) + { + this.OnLongitudeChanging(value); + this.SendPropertyChanging(); + this._Longitude = value; + this.SendPropertyChanged("Longitude"); + this.OnLongitudeChanged(); + } + } + } + + [Association(Name="Dinner_RSVP", Storage="_RSVPs", ThisKey="DinnerID", OtherKey="DinnerID")] + public EntitySet RSVPs + { + get + { + return this._RSVPs; + } + set + { + this._RSVPs.Assign(value); + } + } + + public event PropertyChangingEventHandler PropertyChanging; + + public event PropertyChangedEventHandler PropertyChanged; + + protected virtual void SendPropertyChanging() + { + if ((this.PropertyChanging != null)) + { + this.PropertyChanging(this, emptyChangingEventArgs); + } + } + + protected virtual void SendPropertyChanged(String propertyName) + { + if ((this.PropertyChanged != null)) + { + this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } + + private void attach_RSVPs(RSVP entity) + { + this.SendPropertyChanging(); + entity.Dinner = this; + } + + private void detach_RSVPs(RSVP entity) + { + this.SendPropertyChanging(); + entity.Dinner = null; + } + } + + [Table(Name="dbo.RSVP")] + public partial class RSVP : INotifyPropertyChanging, INotifyPropertyChanged + { + + private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty); + + private int _RsvpID; + + private int _DinnerID; + + private string _AttendeeName; + + private EntityRef _Dinner; + + #region Extensibility Method Definitions + partial void OnLoaded(); + partial void OnValidate(System.Data.Linq.ChangeAction action); + partial void OnCreated(); + partial void OnRsvpIDChanging(int value); + partial void OnRsvpIDChanged(); + partial void OnDinnerIDChanging(int value); + partial void OnDinnerIDChanged(); + partial void OnAttendeeNameChanging(string value); + partial void OnAttendeeNameChanged(); + #endregion + + public RSVP() + { + this._Dinner = default(EntityRef); + OnCreated(); + } + + [Column(Storage="_RsvpID", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)] + public int RsvpID + { + get + { + return this._RsvpID; + } + set + { + if ((this._RsvpID != value)) + { + this.OnRsvpIDChanging(value); + this.SendPropertyChanging(); + this._RsvpID = value; + this.SendPropertyChanged("RsvpID"); + this.OnRsvpIDChanged(); + } + } + } + + [Column(Storage="_DinnerID", DbType="Int NOT NULL")] + public int DinnerID + { + get + { + return this._DinnerID; + } + set + { + if ((this._DinnerID != value)) + { + if (this._Dinner.HasLoadedOrAssignedValue) + { + throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException(); + } + this.OnDinnerIDChanging(value); + this.SendPropertyChanging(); + this._DinnerID = value; + this.SendPropertyChanged("DinnerID"); + this.OnDinnerIDChanged(); + } + } + } + + [Column(Storage="_AttendeeName", DbType="NVarChar(50) NOT NULL", CanBeNull=false)] + public string AttendeeName + { + get + { + return this._AttendeeName; + } + set + { + if ((this._AttendeeName != value)) + { + this.OnAttendeeNameChanging(value); + this.SendPropertyChanging(); + this._AttendeeName = value; + this.SendPropertyChanged("AttendeeName"); + this.OnAttendeeNameChanged(); + } + } + } + + [Association(Name="Dinner_RSVP", Storage="_Dinner", ThisKey="DinnerID", OtherKey="DinnerID", IsForeignKey=true)] + public Dinner Dinner + { + get + { + return this._Dinner.Entity; + } + set + { + Dinner previousValue = this._Dinner.Entity; + if (((previousValue != value) + || (this._Dinner.HasLoadedOrAssignedValue == false))) + { + this.SendPropertyChanging(); + if ((previousValue != null)) + { + this._Dinner.Entity = null; + previousValue.RSVPs.Remove(this); + } + this._Dinner.Entity = value; + if ((value != null)) + { + value.RSVPs.Add(this); + this._DinnerID = value.DinnerID; + } + else + { + this._DinnerID = default(int); + } + this.SendPropertyChanged("Dinner"); + } + } + } + + public event PropertyChangingEventHandler PropertyChanging; + + public event PropertyChangedEventHandler PropertyChanged; + + protected virtual void SendPropertyChanging() + { + if ((this.PropertyChanging != null)) + { + this.PropertyChanging(this, emptyChangingEventArgs); + } + } + + protected virtual void SendPropertyChanged(String propertyName) + { + if ((this.PropertyChanged != null)) + { + this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } + } + + public partial class NearestDinnersResult + { + + private int _DinnerID; + + public NearestDinnersResult() + { + } + + [Column(Storage="_DinnerID", DbType="Int NOT NULL")] + public int DinnerID + { + get + { + return this._DinnerID; + } + set + { + if ((this._DinnerID != value)) + { + this._DinnerID = value; + } + } + } + } +} +#pragma warning restore 1591 diff --git a/aspclassiccompiler/NerdDinnerAsp/Models/RuleViolation.cs b/aspclassiccompiler/NerdDinnerAsp/Models/RuleViolation.cs new file mode 100644 index 0000000..f3244f2 --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Models/RuleViolation.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace NerdDinner.Models { + + public class RuleViolation { + + public string ErrorMessage { get; private set; } + public string PropertyName { get; private set; } + + public RuleViolation(string errorMessage) { + ErrorMessage = errorMessage; + } + + public RuleViolation(string errorMessage, string propertyName) { + ErrorMessage = errorMessage; + PropertyName = propertyName; + } + } +} diff --git a/aspclassiccompiler/NerdDinnerAsp/NerdDinnerAsp.csproj b/aspclassiccompiler/NerdDinnerAsp/NerdDinnerAsp.csproj new file mode 100644 index 0000000..b63e41c --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/NerdDinnerAsp.csproj @@ -0,0 +1,196 @@ + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {328C148C-DBEE-41A4-B1C7-104CBB216556} + {603c0e0b-db56-11dc-be95-000d561079b0};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + NerdDinner + NerdDinner + v3.5 + false + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\ + TRACE + prompt + 4 + + + + + + + 3.5 + + + 3.5 + + + 3.5 + + + False + C:\Program Files\Microsoft ASP.NET\ASP.NET MVC RC\Assemblies\System.Web.Abstractions.dll + 3.5 + + + C:\Program Files\Microsoft ASP.NET\ASP.NET MVC RC\Assemblies\System.Web.Mvc.dll + False + True + + + False + C:\Program Files\Microsoft ASP.NET\ASP.NET MVC RC\Assemblies\System.Web.Routing.dll + 3.5 + + + 3.5 + + + + + + + + + + + + + + + + + Code + + + Default.aspx + ASPXCodeBehind + + + Global.asax + + + + + + + + + True + True + NerdDinner.dbml + + + + + + + + + NerdDinner.mdf + + + + + + + + + + + + + + ASPXCodeBehind + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MSLinqToSQLGenerator + NerdDinner.designer.cs + Designer + + + + + + + + NerdDinner.dbml + + + + + + + + + + + + + False + True + 60848 + / + + + False + False + + + False + + + + + \ No newline at end of file diff --git a/aspclassiccompiler/NerdDinnerAsp/NerdDinnerAsp.csproj.user b/aspclassiccompiler/NerdDinnerAsp/NerdDinnerAsp.csproj.user new file mode 100644 index 0000000..4d6e175 --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/NerdDinnerAsp.csproj.user @@ -0,0 +1,36 @@ + + + ShowAllFiles + + + + + + + + CurrentPage + True + False + False + False + RunFiles + + + False + True + + + + + + + + + False + True + False + + + + + \ No newline at end of file diff --git a/aspclassiccompiler/NerdDinnerAsp/Properties/AssemblyInfo.cs b/aspclassiccompiler/NerdDinnerAsp/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a60c7ec --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NerdDinner")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NerdDinner")] +[assembly: AssemblyCopyright("Copyright © 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("3f961952-a5a3-4ca2-bc29-5b46b500177d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("0.5.2.32072")] diff --git a/aspclassiccompiler/NerdDinnerAsp/Scripts/Map.js b/aspclassiccompiler/NerdDinnerAsp/Scripts/Map.js new file mode 100644 index 0000000..b30aba7 --- /dev/null +++ b/aspclassiccompiler/NerdDinnerAsp/Scripts/Map.js @@ -0,0 +1,138 @@ +/// + +var map = null; +var points = []; +var shapes = []; +var center = null; + +function LoadMap(latitude, longitude, onMapLoaded) { + map = new VEMap('theMap'); + options = new VEMapOptions(); + options.EnableBirdseye = false; + + // Makes the control bar less obtrusize. + map.SetDashboardSize(VEDashboardSize.Small); + + if (onMapLoaded != null) + map.onLoadMap = onMapLoaded; + + if (latitude != null && longitude != null) { + center = new VELatLong(latitude, longitude); + } + + map.LoadMap(center, null, null, null, null, null, null, options); +} + +function LoadPin(LL, name, description) { + var shape = new VEShape(VEShapeType.Pushpin, LL); + + //Make a nice Pushpin shape with a title and description + shape.SetTitle(" " + escape(name) + ""); + if (description !== undefined) { + shape.SetDescription("

" + + escape(description) + "

"); + } + map.AddShape(shape); + points.push(LL); + shapes.push(shape); +} + +function FindAddressOnMap(where) { + var numberOfResults = 20; + var setBestMapView = true; + var showResults = true; + + map.Find("", where, null, null, null, + numberOfResults, showResults, true, true, + setBestMapView, callbackForLocation); +} + +function callbackForLocation(layer, resultsArray, places, + hasMore, VEErrorMessage) { + + clearMap(); + + if (places == null) + return; + + //Make a pushpin for each place we find + $.each(places, function(i, item) { + var description = ""; + if (item.Description !== undefined) { + description = item.Description; + } + var LL = new VELatLong(item.LatLong.Latitude, + item.LatLong.Longitude); + + LoadPin(LL, item.Name, description); + }); + + //Make sure all pushpins are visible + if (points.length > 1) { + map.SetMapView(points); + } + + //If we've found exactly one place, that's our address. + if (points.length === 1) { + $("#Latitude").val(points[0].Latitude); + $("#Longitude").val(points[0].Longitude); + } +} + +function clearMap() { + map.Clear(); + points = []; + shapes = []; +} + +function FindDinnersGivenLocation(where) { + map.Find("", where, null, null, null, null, null, false, + null, null, callbackUpdateMapDinners); +} + +function callbackUpdateMapDinners(layer, resultsArray, places, hasMore, VEErrorMessage) { + $("#dinnerList").empty(); + clearMap(); + var center = map.GetCenter(); + + $.post("/Search/SearchByLocation", { latitude: center.Latitude, + longitude: center.Longitude + }, function(dinners) { + $.each(dinners, function(i, dinner) { + + var LL = new VELatLong(dinner.Latitude, dinner.Longitude, 0, null); + + var RsvpMessage = ""; + + if (dinner.RSVPCount == 1) + RsvpMessage = "" + dinner.RSVPCount + " RSVP"; + else + RsvpMessage = "" + dinner.RSVPCount + " RSVPs"; + + // Add Pin to Map + LoadPin(LL, '' + + dinner.Title + '', + "

" + dinner.Description + "

" + RsvpMessage); + + //Add a dinner to the