Skip to content
Browse files

Photo Sharing site before PayPal integration

  • Loading branch information...
1 parent 005ef95 commit 49aa245424c5e6dced960198250afdcc8e2d62f9 @rasesh rasesh committed Mar 28, 2011
Showing with 1,601 additions and 0 deletions.
  1. +63 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Account/Login.cshtml
  2. +4 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Account/Logout.cshtml
  3. +96 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Account/Register.cshtml
  4. +18 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/App_Code/EnumerableExtensions.cs
  5. +146 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/App_Code/MultiThumbnailGenerator.cs
  6. +13 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/App_Code/PhotoGallery.cshtml
  7. BIN OrlandoCodeCamp/PhotoSharing-No-Payment/App_Data/PhotoGallery.sdf
  8. BIN ...otoSharing-No-Payment/App_Data/packages/microsoft-web-helpers.1.0/microsoft-web-helpers.1.0.nupkg
  9. +4 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Default.cshtml
  10. +31 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Gallery/Default.cshtml
  11. +42 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Gallery/New.cshtml
  12. +35 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Gallery/Thumbnail.cshtml
  13. +49 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Gallery/Upload.cshtml
  14. +41 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Gallery/View.cshtml
  15. BIN OrlandoCodeCamp/PhotoSharing-No-Payment/Images/download.png
  16. BIN OrlandoCodeCamp/PhotoSharing-No-Payment/Images/gallery-empty.png
  17. BIN OrlandoCodeCamp/PhotoSharing-No-Payment/Images/header-bkg.png
  18. BIN OrlandoCodeCamp/PhotoSharing-No-Payment/Images/icon-account.png
  19. BIN OrlandoCodeCamp/PhotoSharing-No-Payment/Images/icon-gallery.png
  20. BIN OrlandoCodeCamp/PhotoSharing-No-Payment/Images/icon-tags.png
  21. +58 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Photo/Edit.cshtml
  22. +68 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Photo/EditTags.cshtml
  23. +15 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Photo/Full.cshtml
  24. +45 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Photo/Remove.cshtml
  25. +38 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Photo/Thumbnail.cshtml
  26. +128 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Photo/View.cshtml
  27. +456 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Styles/Site.css
  28. +30 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Tag/Default.cshtml
  29. +33 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Tag/Thumbnail.cshtml
  30. +45 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/Tag/View.cshtml
  31. +48 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/User/Default.cshtml
  32. +53 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/User/View.cshtml
  33. +3 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/_AppStart.cshtml
  34. +4 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/_PageStart.cshtml
  35. +33 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/_SiteLayout.cshtml
  36. BIN OrlandoCodeCamp/PhotoSharing-No-Payment/bin/Microsoft.Web.Helpers.dll
  37. BIN OrlandoCodeCamp/PhotoSharing-No-Payment/favicon.ico
  38. +2 −0 OrlandoCodeCamp/PhotoSharing-No-Payment/robots.txt
View
63 OrlandoCodeCamp/PhotoSharing-No-Payment/Account/Login.cshtml
@@ -0,0 +1,63 @@
+@{
+ Page.Title = "Login";
+
+ if (IsPost) {
+ var email = Request["email"];
+ if (email.IsEmpty()) {
+ ModelState.AddError("email", "You must specify an email address.");
+ }
+
+ var password = Request["password"];
+ if (password.IsEmpty()) {
+ ModelState.AddError("password", "You must specify a password.");
+ }
+
+ if (ModelState.IsValid) {
+ var rememberMe = Request["rememberMe"].AsBool();
+ if (WebSecurity.Login(email, password, rememberMe)) {
+ string returnUrl = Request["returnUrl"];
+ if (!returnUrl.IsEmpty()) {
+ Context.RedirectLocal(returnUrl);
+ } else{
+ Response.Redirect("~/");
+ }
+ } else {
+ ModelState.AddFormError("The email or password provided is incorrect.");
+ }
+ }
+ }
+}
+
+<h1>Login</h1>
+
+<p>
+ Please enter your email and password below. If you don't have an account,
+ please <a href="@Href("Register")">Register</a>.
+</p>
+
+@Html.ValidationSummary(excludeFieldErrors: true)
+
+<form method="post" action="">
+ <fieldset class="no-legend">
+ <legend>Login</legend>
+ <ol>
+ <li class="email">
+ <label for="email">Email</label>
+ <input type="text" id="email" name="email" title="Email Address" placeholder="Email address" class="@PhotoGallery.GetValidationClass("email")" />
+ @Html.ValidationMessage("email")
+ </li>
+ <li class="Password">
+ <label for="password">Password</label>
+ <input type="password" id="password" name="password" title="Password" class="@PhotoGallery.GetValidationClass("password")" />
+ @Html.ValidationMessage("password")
+ </li>
+ <li class="remember-me">
+ <label class="checkbox" for="rememberMe">Remember Me?</label>
+ <input type="checkbox" id="rememberMe" name="rememberMe" value="true" title="Remember Me" />
+ </li>
+ </ol>
+ <p class="form-actions">
+ <input type="submit" value="Login" title="Login" />
+ </p>
+ </fieldset>
+</form>
View
4 OrlandoCodeCamp/PhotoSharing-No-Payment/Account/Logout.cshtml
@@ -0,0 +1,4 @@
+@{
+ WebSecurity.Logout();
+ Response.Redirect("~/");
+}
View
96 OrlandoCodeCamp/PhotoSharing-No-Payment/Account/Register.cshtml
@@ -0,0 +1,96 @@
+@{
+ Page.Title = "Register";
+
+ if (IsPost) {
+ //if (!ReCaptcha.Validate("PRIVATE_KEY")) {
+ // ModelState.AddFormError("Captcha response was not correct.");
+ //}
+
+ var email = Request["email"];
+ if (email.IsEmpty()) {
+ ModelState.AddError("email", "You must specify an email address.");
+ }
+
+ var password = Request["password"];
+ var confirmPassword = Request["confirmPassword"];
+
+ if (password.IsEmpty()) {
+ ModelState.AddError("password", "You must specify a password.");
+ }
+
+ if (confirmPassword.IsEmpty()) {
+ ModelState.AddError("confirmPassword", "You must specify a confirm password.");
+ }
+
+ if (password != confirmPassword) {
+ ModelState.AddFormError("The new password and confirmation password do not match.");
+ }
+
+ if (ModelState.IsValid) {
+ // Create the user profile
+ var db = Database.Open("PhotoGallery");
+
+ // Check if user already exists
+ var user = db.QuerySingle("SELECT Email FROM UserProfiles WHERE LOWER(Email) = LOWER(@0)", email);
+ if (user == null) {
+ // Insert email into the profile table
+ db.Execute("INSERT INTO UserProfiles (Email, DisplayName, Bio) VALUES (@0, @1, @2)", email, email, "");
+
+ // Create and associate a new entry in the membership database.
+ // If successful, continue processing the request
+ try {
+ WebSecurity.CreateAccount(email, password);
+ WebSecurity.Login(email, password);
+ Response.Redirect("~/");
+ } catch (System.Web.Security.MembershipCreateUserException e) {
+ ModelState.AddFormError(e.ToString());
+ }
+ } else {
+ // User already exists
+ ModelState.AddFormError("Email address is already in use.");
+ }
+ }
+ }
+}
+
+<h1>Account Creation</h1>
+<p>
+ Use the form below to create a new account.
+</p>
+
+@Html.ValidationSummary(excludeFieldErrors: true)
+
+<form method="post" action="">
+ <fieldset class="no-legend">
+ <legend>Account Creation</legend>
+ <ol>
+ <li class="email">
+ <label for="email">Email:</label>
+ <input type="text" id="email" name="email" title="Email address" placeholder="Email address" class="@PhotoGallery.GetValidationClass("email")" />
+ @Html.ValidationMessage("email")
+ </li>
+ <li class="password">
+ <label for="password">Password:</label>
+ <input type="password" id="password" name="password" title="Password" class="@PhotoGallery.GetValidationClass("password")" />
+ @Html.ValidationMessage("password")
+ </li>
+ <li class="confirm-password">
+ <label for="confirmPassword">Confirm Password:</label>
+ <input type="password" id="confirmPassword" name="confirmPassword" title="Confirm password" class="@PhotoGallery.GetValidationClass("confirmPassword")" />
+ @Html.ValidationMessage("confirmPassword")
+ </li>
+ <li class="recaptcha">
+ <div class="message info">
+ <p>To enable CAPTCHA verification, uncomment ReCaptcha.GetHtml and replace 'PUBLIC_KEY'
+ with your public key. At the top of this page, uncomment ReCaptcha.Validate and
+ replace 'PRIVATE_KEY' with your private key.</p>
+ <p>Register for reCAPTCHA keys at <a href="http://recaptcha.net">reCAPTCHA.net</a>.</p>
+ </div>
+ @*@ReCaptcha.GetHtml("PUBLIC_KEY", theme: "white")*@
+ </li>
+ </ol>
+ <p class="form-actions">
+ <input type="submit" value="Register" title="Register" />
+ </p>
+ </fieldset>
+</form>
View
18 OrlandoCodeCamp/PhotoSharing-No-Payment/App_Code/EnumerableExtensions.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+public static class EnumerableExtensions {
+
+ public static IEnumerable<TSource> Shuffle<TSource>(this IEnumerable<TSource> source) {
+ List<TSource> list = source.ToList();
+ Random random = new Random();
+
+ for (int i = list.Count - 1; i >= 0; i--) {
+ int r = random.Next(i + 1);
+ yield return list[r];
+ list[r] = list[i];
+ }
+ }
+
+}
View
146 OrlandoCodeCamp/PhotoSharing-No-Payment/App_Code/MultiThumbnailGenerator.cs
@@ -0,0 +1,146 @@
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.IO;
+
+public class MultiThumbnailGenerator : IDisposable {
+ /* common variables */
+ private static int imageDimension = 200;
+ private static float maxMultiplier = 0.7f;
+ private static float maxDimension = (float)imageDimension * maxMultiplier;
+ private static float thinLineWidth = 0.6f;
+ private static float thickLineWidth = 2.0f;
+ private static float maxAngle = 25f;
+
+ /* instance variables */
+ private Random random = new Random();
+ private Bitmap surfaceBitmap = new Bitmap(imageDimension, imageDimension);
+ private Graphics surfaceGraphics;
+ private RectangleF? surfaceBounds;
+
+ public MultiThumbnailGenerator() {
+ surfaceGraphics = Graphics.FromImage(surfaceBitmap);
+ surfaceGraphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
+ surfaceGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
+ }
+
+ public void AddImage(Image image) {
+ // scale image
+ float widthMultiplier = maxDimension / (float)image.Width;
+ float heightMultiplier = maxDimension / (float)image.Height;
+ float minMultiplier = Math.Min(Math.Min(widthMultiplier, heightMultiplier), 1f);
+ float newWidth = minMultiplier * (float)image.Width;
+ float newHeight = minMultiplier * (float)image.Height;
+
+ // choose a random translation & rotation
+ float angle = GetRandomAngle();
+ PointF newDimensions = RotateAndFindNewDimensions(new PointF(newWidth, newHeight), angle);
+ PointF offset = GetRandomOffset(newDimensions);
+ surfaceGraphics.TranslateTransform(offset.X, offset.Y);
+ surfaceGraphics.RotateTransform(angle);
+
+ // draw borders + image
+ DrawRectangle(Brushes.White, newWidth, newHeight, thickLineWidth);
+ DrawRectangle(Brushes.Black, newWidth, newHeight, thinLineWidth);
+ surfaceGraphics.DrawImage(image, -newWidth / 2f, -newHeight / 2f, newWidth, newHeight);
+
+ // calculate new image boundaries
+ RectangleF newBounds = new RectangleF(
+ offset.X - newDimensions.X / 2f,
+ offset.Y - newDimensions.Y / 2f,
+ newDimensions.X,
+ newDimensions.Y);
+
+ if (surfaceBounds.HasValue) {
+ surfaceBounds = Union(surfaceBounds.Value, newBounds);
+ } else {
+ surfaceBounds = newBounds;
+ }
+
+ surfaceGraphics.ResetTransform();
+ }
+
+ private void DrawRectangle(Brush brush, float width, float height, float lineWidth) {
+ surfaceGraphics.FillRectangle(brush,
+ -width / 2f - lineWidth,
+ -height / 2f - lineWidth,
+ width + 2f * lineWidth,
+ height + 2f * lineWidth);
+ }
+
+ private static PointF RotateAndFindNewDimensions(PointF point, float angle) {
+ using (Matrix matrix = new Matrix()) {
+ PointF[] points = new PointF[] {
+ new PointF(0f, 0f),
+ new PointF(0f, point.Y),
+ new PointF(point.X, 0f),
+ new PointF(point.X, point.Y)
+ };
+
+ matrix.Rotate(angle);
+ matrix.TransformPoints(points);
+ float minX = points[0].X;
+ float maxX = minX;
+ float minY = points[0].Y;
+ float maxY = minY;
+ for (int i = 1; i < 4; i++) {
+ minX = Math.Min(minX, points[i].X);
+ maxX = Math.Max(maxX, points[i].X);
+ minY = Math.Min(minY, points[i].Y);
+ maxY = Math.Max(maxY, points[i].Y);
+ }
+
+ return new PointF(maxX - minX, maxY - minY);
+ }
+ }
+
+ private static RectangleF Union(RectangleF oldBounds, RectangleF newBounds) {
+ float left = Math.Min(oldBounds.Left, newBounds.Left);
+ float top = Math.Min(oldBounds.Top, newBounds.Top);
+ float right = Math.Max(oldBounds.Right, newBounds.Right);
+ float bottom = Math.Max(oldBounds.Bottom, newBounds.Bottom);
+ return new RectangleF(left, top, right - left, bottom - top);
+ }
+
+ private float GetRandomAngle() {
+ float r = (float)random.NextDouble();
+ return (r * 2f - 1f) * maxAngle;
+ }
+
+ private PointF GetRandomOffset(PointF dimensions) {
+ float deltaX = (float)imageDimension - dimensions.X - 2f * (thinLineWidth + 1f);
+ float deltaY = (float)imageDimension - dimensions.Y - 2f * (thinLineWidth + 1f);
+
+ float rX = (float)random.NextDouble();
+ float rY = (float)random.NextDouble();
+
+ float newX = (deltaX * rX) + (dimensions.X / 2f) + thinLineWidth + 1f;
+ float newY = (deltaY * rY) + (dimensions.Y / 2f) + thinLineWidth + 1f;
+
+ return new PointF(newX, newY);
+ }
+
+ public void Dispose() {
+ surfaceGraphics.Dispose();
+ surfaceBitmap.Dispose();
+ }
+
+ public void WritePngToStream(Stream outStream) {
+ using (Bitmap outBitmap = new Bitmap(imageDimension, imageDimension)) {
+ using (Graphics outGraphics = Graphics.FromImage(outBitmap)) {
+
+ outGraphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
+ outGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
+
+ // center the image
+ RectangleF bounds = surfaceBounds ?? new RectangleF();
+ float deltaX = (imageDimension - bounds.Width) / 2f - bounds.Left;
+ float deltaY = (imageDimension - bounds.Height) / 2f - bounds.Top;
+ outGraphics.DrawImage(surfaceBitmap, new PointF(deltaX, deltaY));
+
+ outBitmap.Save(outStream, System.Drawing.Imaging.ImageFormat.Png);
+ }
+ }
+ }
+
+}
View
13 OrlandoCodeCamp/PhotoSharing-No-Payment/App_Code/PhotoGallery.cshtml
@@ -0,0 +1,13 @@
+@helper GetValidationClass(string fieldName) {
+ var p = CurrentPage as WebPage;
+ if (p == null) {
+ return;
+ }
+
+ var className = "input-validation-valid";
+ var modelState = p.ModelState[fieldName];
+ if (modelState != null && modelState.Errors.Count != 0) {
+ className = "input-validation-error";
+ }
+ @className
+}
View
BIN OrlandoCodeCamp/PhotoSharing-No-Payment/App_Data/PhotoGallery.sdf
Binary file not shown.
View
BIN ...ng-No-Payment/App_Data/packages/microsoft-web-helpers.1.0/microsoft-web-helpers.1.0.nupkg
Binary file not shown.
View
4 OrlandoCodeCamp/PhotoSharing-No-Payment/Default.cshtml
@@ -0,0 +1,4 @@
+@{
+ // Redirect to the start page that we want
+ Response.Redirect("~/Gallery");
+}
View
31 OrlandoCodeCamp/PhotoSharing-No-Payment/Gallery/Default.cshtml
@@ -0,0 +1,31 @@
+@{
+ Page.Title = "Photo Gallery";
+
+ var db = Database.Open("PhotoGallery");
+ var galleries = db.Query(@"SELECT Galleries.Id, Galleries.Name, COUNT(Photos.Id) AS PhotoCount
+ FROM Galleries LEFT OUTER JOIN Photos ON Galleries.Id = Photos.GalleryId
+ GROUP BY Galleries.Id, Galleries.Name").ToList();
+}
+
+<h1>Galleries</h1>
+@if (galleries.Count == 1) {
+ <p>There is one gallery.</p>
+} else {
+ <p>There are @galleries.Count galleries.</p>
+}
+<ul class="thumbnails gallery">
+ @foreach (var gallery in galleries) {
+ <li class="gallery">
+ <a href="@Href("~/Gallery/View", gallery.Id)">
+ <img alt="Images from @gallery.Name" src="@Href("~/Gallery/Thumbnail", gallery.Id)" class="thumbnail-no-border" />
+ <span class="below-image">@gallery.Name</span>
+ <span class="image-overlay">@gallery.PhotoCount photo(s)</span>
+ </a>
+ </li>
+ }
+</ul>
+<p class="actions">
+@if (WebSecurity.IsAuthenticated) {
+ <a href="@Href("~/Gallery/New")">Create a New Gallery</a>
+}
+</p>
View
42 OrlandoCodeCamp/PhotoSharing-No-Payment/Gallery/New.cshtml
@@ -0,0 +1,42 @@
+@{
+ WebSecurity.RequireAuthenticatedUser();
+
+ Page.Title = "New Gallery";
+
+ if (IsPost) {
+ var galleryName = Request["Name"];
+ if (galleryName.IsEmpty()) {
+ ModelState.AddError("Name", "You must specify a gallery name.");
+ }
+ if (ModelState.IsValid) {
+ var db = Database.Open("PhotoGallery");
+ var nameExists = db.QueryValue("SELECT COUNT(*) FROM Galleries WHERE LOWER(Name) = LOWER(@0)", galleryName) > 0;
+ if (nameExists) {
+ ModelState.AddError("Name", "A gallery with the supplied name already exists.");
+ } else {
+ //Create Gallery
+ db.Execute("INSERT INTO Galleries (Name) VALUES (@0)", galleryName);
+ // And redirect
+ Response.Redirect(Href("View", db.GetLastInsertId()));
+ }
+ }
+ }
+}
+
+<h1>New Gallery</h1>
+<form method="post" action="">
+ <fieldset>
+ <legend>New Gallery</legend>
+ <ol>
+ <li>
+ <label for="name">Name</label>
+ <input type="text" id="name" name="name" title="Gallery name" placeholder="Gallery name" class="@PhotoGallery.GetValidationClass("name")" />
+ @Html.ValidationMessage("Name")
+ </li>
+ </ol>
+ <p class="form-actions">
+ <input type="submit" value="Create" title="Create gallery" />
+ <a href="@Href("~/Gallery")" title="Return to galleries">Cancel</a>
+ </p>
+ </fieldset>
+</form>
View
35 OrlandoCodeCamp/PhotoSharing-No-Payment/Gallery/Thumbnail.cshtml
@@ -0,0 +1,35 @@
+@{
+ // Cache the image for a minute
+ Response.OutputCache(60);
+
+ var galleryId = UrlData[0].AsInt();
+
+ var db = Database.Open("PhotoGallery");
+
+ var gallery = db.QuerySingle("SELECT * FROM Galleries WHERE Id = @0", galleryId);
+ if (gallery == null) {
+ Response.SetStatus(HttpStatusCode.NotFound);
+ return;
+ }
+
+ var photos = db.Query("SELECT TOP(3) FileContents, UploadDate FROM Photos WHERE GalleryId = @0 ORDER BY UploadDate DESC", galleryId);
+ if (photos.Count() == 0) {
+ Response.Redirect("~/Images/gallery-empty.png");
+ return;
+ }
+
+ using (var generator = new MultiThumbnailGenerator()) {
+ foreach (var photo in photos) {
+ using (var imageStream = new System.IO.MemoryStream(photo.FileContents)) {
+ using (var image = System.Drawing.Image.FromStream(imageStream)) {
+ generator.AddImage(image);
+ }
+ }
+ }
+ using (var outStream = new System.IO.MemoryStream()) {
+ generator.WritePngToStream(outStream);
+ var image = new WebImage(outStream);
+ image.Write();
+ }
+ }
+}
View
49 OrlandoCodeCamp/PhotoSharing-No-Payment/Gallery/Upload.cshtml
@@ -0,0 +1,49 @@
+@{
+ WebSecurity.RequireAuthenticatedUser();
+
+ var galleryId = UrlData[0].AsInt();
+
+ var db = Database.Open("PhotoGallery");
+
+ var gallery = db.QuerySingle("SELECT * FROM Galleries WHERE Id = @0", galleryId);
+ if (gallery == null) {
+ Response.SetStatus(HttpStatusCode.NotFound);
+ return;
+ }
+
+ Page.Title = "Upload Photo to Gallery - " + gallery.Name;
+ if (IsPost) {
+ var numFiles = Request.Files.Count;
+ for (int i = 0; i < numFiles; i++) {
+ var file = Request.Files[i];
+ if (file.ContentLength > 0) {
+ var fileUpload = new WebImage(file.InputStream);
+ var fileTitle = Path.GetFileNameWithoutExtension(file.FileName).Trim();
+ if (fileTitle.IsEmpty()) {
+ fileTitle = "Untitled";
+ }
+ var fileExtension = Path.GetExtension(file.FileName).Trim();
+ var fileBytes = fileUpload.GetBytes();
+ db.Execute(@"INSERT INTO Photos
+ (GalleryId, UserId, Description, FileTitle, FileExtension, ContentType, FileSize, UploadDate, FileContents) VALUES
+ (@0, @1, @2, @3, @4, @5, @6, @7, @8)", galleryId, WebSecurity.CurrentUserId, "", fileTitle, fileExtension,
+ fileUpload.ImageFormat, fileBytes.Length, DateTime.Now, fileBytes);
+ }
+ }
+ Response.Redirect(Href("~/Photo/View", db.GetLastInsertId()));
+ }
+}
+
+<h1>Upload Photo</h1>
+
+<p>
+ The photo you upload will be placed in the
+ <a class="italic" href="@Href("View", galleryId)">@gallery.Name</a> gallery.
+</p>
+
+@FileUpload.GetHtml()
+
+
+<div class="message info">
+ The default file size is limited to 4MB. To change this you will need to update the 'HttpRuntimeSection/MaxRequestLength' section in web.config.
+</div>
View
41 OrlandoCodeCamp/PhotoSharing-No-Payment/Gallery/View.cshtml
@@ -0,0 +1,41 @@
+@{
+ var galleryId = UrlData[0].AsInt();
+
+ var db = Database.Open("PhotoGallery");
+
+ var gallery = db.QuerySingle("SELECT * FROM Galleries WHERE Id = @0", galleryId);
+ if (gallery == null) {
+ Response.SetStatus(HttpStatusCode.NotFound);
+ return;
+ }
+
+ // Found a match - so show all its photos
+ var photos = db.Query("SELECT Id, FileTitle FROM Photos WHERE GalleryId = @0", galleryId).ToList();
+
+ Page.Title = "Gallery - " + gallery.Name;
+}
+
+<h1>@gallery.Name</h1>
+
+@if (photos.Count == 1) {
+ <p>This gallery contains one photo.</p>
+} else {
+ <p>This gallery contains @photos.Count photos.</p>
+}
+
+<ul class="thumbnails">
+ @foreach (var photo in photos) {
+ <li>
+ <a href="@Href("~/Photo/View", photo.Id)">
+ <img alt="thumbnail of @Path.GetFileNameWithoutExtension(photo.FileTitle)" src="@Href("~/Photo/Thumbnail", photo.Id)" class="thumbnail-border" />
+ <span class="image-overlay">@Path.GetFileNameWithoutExtension(photo.FileTitle)</span>
+ </a>
+ </li>
+ }
+</ul>
+
+@if (WebSecurity.IsAuthenticated) {
+ <p class="actions">
+ <a href="@Href("~/Gallery/Upload", galleryId)">Upload a Photo</a>
+ </p>
+}
View
BIN OrlandoCodeCamp/PhotoSharing-No-Payment/Images/download.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN OrlandoCodeCamp/PhotoSharing-No-Payment/Images/gallery-empty.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN OrlandoCodeCamp/PhotoSharing-No-Payment/Images/header-bkg.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN OrlandoCodeCamp/PhotoSharing-No-Payment/Images/icon-account.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN OrlandoCodeCamp/PhotoSharing-No-Payment/Images/icon-gallery.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN OrlandoCodeCamp/PhotoSharing-No-Payment/Images/icon-tags.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
58 OrlandoCodeCamp/PhotoSharing-No-Payment/Photo/Edit.cshtml
@@ -0,0 +1,58 @@
+@{
+ var photoId = UrlData[0].AsInt();
+
+ var db = Database.Open("PhotoGallery");
+
+ var photo = db.QuerySingle("SELECT * FROM Photos WHERE Id = @0", photoId);
+ if (photo == null) {
+ Response.SetStatus(HttpStatusCode.NotFound);
+ return;
+ }
+
+ WebSecurity.RequireUser(photo.UserId);
+
+ Page.Title = "Edit Photo - " + photo.FileTitle;
+
+ if (IsPost) {
+ var fileTitle = Request["FileTitle"];
+ if (fileTitle.IsEmpty()) {
+ ModelState.AddError("FileTitle", "You must specify a name");
+ }
+ var description = Request["Description"];
+ if (description.IsEmpty()) {
+ ModelState.AddError("Description", "You must specify a description");
+ }
+ if (ModelState.IsValid) {
+ db.Execute("UPDATE Photos SET FileTitle = @0, Description= @1 WHERE Id = @2", fileTitle, description, photoId);
+ Response.Redirect(Href("View", photo.Id));
+ }
+ }
+}
+
+<div class="sidebar">
+ <h1>Edit Photo</h1>
+ <form method="post" action="">
+ <fieldset class="no-legend">
+ <legend>Edit Photo</legend>
+ <ol>
+ <li>
+ <label for="fileTitle">Name:</label>
+ <input type="text" id="fileTitle" name="fileTitle" title="Photo name" value="@photo.FileTitle" placeholder="Photo Name" class="@PhotoGallery.GetValidationClass("fileTitle")" />
+ @Html.ValidationMessage("FileTitle")
+ </li>
+ <li>
+ <label for="description">Description:</label>
+ <textarea id="description" name="description" title="Photo description" rows="4" cols="30" placeholder="Photo description" class="@PhotoGallery.GetValidationClass("description")">@photo.Description</textarea>
+ @Html.ValidationMessage("Description")
+ </li>
+ </ol>
+ <p class="form-actions">
+ <input type="submit" value="Save Changes" title="Save changes" />
+ <a href="@Href("~/Photo/View", photoId)" title="Cancel changes">Cancel</a>
+ </p>
+ </fieldset>
+ </form>
+</div>
+<div class="main">
+ <img alt="@Html.AttributeEncode(photo.FileTitle)" src="@Href("~/Photo/Thumbnail", photo.Id, new { size="large" })" />
+</div>
View
68 OrlandoCodeCamp/PhotoSharing-No-Payment/Photo/EditTags.cshtml
@@ -0,0 +1,68 @@
+@{
+ WebSecurity.RequireAuthenticatedUser();
+
+ var photoId = UrlData[0].AsInt();
+
+ var db = Database.Open("PhotoGallery");
+
+ var photo = db.QuerySingle("SELECT * FROM Photos WHERE Id = @0", photoId);
+ if (photo == null) {
+ Response.SetStatus(HttpStatusCode.NotFound);
+ return;
+ }
+
+ Page.Title = "Photo Tags - " + photo.FileTitle;
+
+ if (IsPost) {
+ var newTags = Request["newTags"];
+ // prepare tags for processing
+ var tagNames = newTags.Split(';');
+
+ //Clear Tags associated with this image
+ db.Execute("DELETE FROM Photos_Tags WHERE Photos_Id = @0", photoId);
+ foreach (string tagName in tagNames) {
+ // get the tag ID for each tag, else create if doesn't exist
+ var trimmed = tagName.Trim();
+ bool exists = db.QueryValue("SELECT COUNT(*) FROM Tags WHERE TagName = @0", trimmed) > 0;
+ if (!exists) {
+ //If tag doesn't exist, create it
+ db.Execute("INSERT INTO Tags (TagName) VALUES (@0)", trimmed);
+ }
+ //Associate image and tag
+ db.Execute("INSERT INTO Photos_Tags (Photos_Id, Tags_TagName) VALUES (@0, @1)", photoId, trimmed);
+ }
+ Response.Redirect(Href("View", photo.Id));
+ }
+
+ // get a list of all the tags for this photo, sorted
+ var tags = db.Query("SELECT TagName FROM Tags, Photos_Tags WHERE Tags_TagName = TagName AND Photos_Id = @0 ORDER BY TagName", photoId);
+
+ var tagsList = new List<string>();
+ foreach (var tag in tags) {
+ tagsList.Add(tag.TagName);
+ }
+ var tagStringToDisplay = String.Join("; ", tagsList.ToArray());
+}
+
+<div class="sidebar">
+ <h1>Edit Photo's Tags</h1>
+ <h2>@photo.FileTitle</h2>
+ <form method="post" action="">
+ <fieldset class="no-legend">
+ <legend>Edit Tags</legend>
+ <ol>
+ <li>
+ <label for="newTags">Enter tags, semicolon-delimited:</label>
+ <textarea id="newTags" name="newTags" title="Enter tags seperated by a semicolon" rows="4" cols="50" placeholder="Enter tags seperated by a semicolon">@tagStringToDisplay</textarea>
+ </li>
+ </ol>
+ <p class="form-actions">
+ <input type="submit" value="Save Changes" title="Save changes" />
+ <a href="@Href("~/Photo/View", photoId)" title="Do not save changes">Cancel</a>
+ </p>
+ </fieldset>
+ </form>
+</div>
+<div class="main">
+ <img alt="@Html.AttributeEncode(photo.FileTitle)" src="@Href("~/Photo/Thumbnail", photo.Id, new { size="large" })" />
+</div>
View
15 OrlandoCodeCamp/PhotoSharing-No-Payment/Photo/Full.cshtml
@@ -0,0 +1,15 @@
+@{
+ // Cache the image for a minute
+ Response.OutputCache(60);
+
+ var photoId = UrlData[0].AsInt();
+ var db = Database.Open("PhotoGallery");
+ var photo = db.QuerySingle("SELECT * FROM Photos WHERE Id = @0", photoId);
+ if (photo == null) {
+ Response.SetStatus(HttpStatusCode.NotFound);
+ return;
+ }
+
+ Response.AppendHeader("Content-Disposition", String.Format("attachment; filename={0}", HttpUtility.UrlPathEncode(photo.FileTitle + photo.FileExtension)));
+ new WebImage(photo.FileContents).Write();
+}
View
45 OrlandoCodeCamp/PhotoSharing-No-Payment/Photo/Remove.cshtml
@@ -0,0 +1,45 @@
+@{
+ var photoId = UrlData[0].AsInt();
+
+ var db = Database.Open("PhotoGallery");
+
+ var photo = db.QuerySingle("SELECT * FROM Photos WHERE Id = @0", photoId);
+ if (photo == null) {
+ Response.SetStatus(HttpStatusCode.NotFound);
+ return;
+ }
+
+ WebSecurity.RequireUser(photo.UserId);
+
+ Page.Title = "Remove Photo - " + photo.FileTitle;
+
+ if (IsPost) {
+ //Remove all tags associated with this image
+ db.Execute("DELETE FROM Photos_Tags WHERE Photos_Id = @0", photoId);
+ //Remove all comments associated with this image
+ db.Execute("DELETE FROM Comments WHERE PhotoId = @0", photoId);
+ //Delete image
+ db.Execute("DELETE FROM Photos WHERE Id = @0", photoId);
+ Response.Redirect(Href("~/Gallery/View",photo.GalleryId));
+ }
+}
+
+<div class="sidebar">
+ <h1>@photo.FileTitle</h1>
+ <h2 class="confirm-removal">Confirm Removal</h2>
+ <p class="message error">
+ Removing this photo will permanently delete the file from the photo gallery site
+ and you will lose all associated data (description, tags, and comments). You may
+ want to download the <a href="@Href("~/Photo/Full", photoId)" title="Download: @(photo.FileTitle + photo.FileExtension)">full size photo</a> before continuing.
+ </p>
+
+ <form method="post" action="">
+ <p class="form-actions">
+ <input type="submit" value="Remove" title="Remove photo" />
+ <a href="@Href("~/Photo/View", photoId)" title="Do not remove photo">Cancel</a>
+ </p>
+ </form>
+</div>
+<div class="main">
+ <img src="@Href("~/Photo/Thumbnail", photo.Id, new { size="large" })" />
+</div>
View
38 OrlandoCodeCamp/PhotoSharing-No-Payment/Photo/Thumbnail.cshtml
@@ -0,0 +1,38 @@
+@{
+ // Cache the image for a minute
+ Response.OutputCache(60);
+
+ var photoId = UrlData[0].AsInt();
+ var db = Database.Open("PhotoGallery");
+ var photo = db.QuerySingle("SELECT * FROM Photos WHERE Id = @0", photoId);
+ if (photo == null) {
+ Response.SetStatus(HttpStatusCode.NotFound);
+ return;
+ }
+
+ var size = Request["size"] ?? "";
+
+ var width = 0;
+ var height = 0;
+ switch (size.ToUpperInvariant()) {
+ case "":
+ case "SMALL":
+ width = 200;
+ height = 200;
+ break;
+ case "MEDIUM":
+ width = 400;
+ height = 300;
+ break;
+ case "LARGE":
+ width = 625;
+ height = 625;
+ break;
+ default:
+ Response.SetStatus(HttpStatusCode.BadRequest);
+ return;
+ }
+
+ var image = new WebImage(photo.FileContents);
+ image.Resize(width, height).Write();
+}
View
128 OrlandoCodeCamp/PhotoSharing-No-Payment/Photo/View.cshtml
@@ -0,0 +1,128 @@
+@{
+ var photoId = UrlData[0].AsInt();
+
+ var db = Database.Open("PhotoGallery");
+
+ var photo = db.QuerySingle("SELECT * FROM Photos WHERE Id = @0", photoId);
+ if (photo == null) {
+ Response.SetStatus(HttpStatusCode.NotFound);
+ return;
+ }
+
+ Page.Title = "Photo - " + photo.FileTitle;
+
+ string description = photo.description;
+
+ if (IsPost) {
+ var newComment = Request["newComment"].Trim();
+ if (newComment.IsEmpty()) {
+ Response.Redirect(Href("View", photoId));
+ }
+
+ db.Execute("INSERT INTO Comments (PhotoId, CommentDate, UserId, CommentText) VALUES (@0, @1, @2, @3)",
+ photoId, DateTime.Now, WebSecurity.CurrentUserId, newComment);
+
+ Response.Redirect(Href("View",photoId));
+ return;
+ }
+
+ // Found a match - so show its info
+ var user = db.QuerySingle("SELECT * FROM UserProfiles WHERE UserId = @0", photo.UserId);
+ var gallery = db.QuerySingle("SELECT * FROM Galleries WHERE Id = @0", photo.GalleryId);
+ var comments = db.Query(@"SELECT * FROM Comments INNER JOIN UserProfiles
+ ON Comments.UserId = UserProfiles.UserId WHERE PhotoId = @0 ORDER BY Comments.CommentDate", photo.Id);
+ var tagList = db.Query("SELECT Tags_TagName FROM Photos_Tags WHERE Photos_Id = @0 ORDER BY Tags_TagName", photo.Id);
+}
+
+<div class="sidebar">
+ <h1>@photo.FileTitle</h1>
+ @if (user.UserId == WebSecurity.CurrentUserId) {
+ <p>
+ As the author, you can <a href="@Href("~/Photo/Edit", photoId)">edit</a>
+ or <a href="@Href("~/Photo/Remove", photoId)">remove</a> this photo.
+ </p>
+ }
+ <dl>
+ <dt class="description">Description</dt>
+ <dd class="description">
+ @if (!description.IsEmpty()) {
+ <text>@photo.Description</text>
+ } else {
+ <text>The uploader did not provide a description for this photo.</text>
+ }
+ </dd>
+ <dt class="uploaded-by">Uploaded by</dt>
+ <dd class="uploaded-by"><a href="@Href("~/User/View", user.UserId)">@user.DisplayName</a></dd>
+ <dt class="upload-date">Upload date</dt>
+ <dd class="upload-date">@photo.UploadDate</dd>
+ <dt class="part-of-gallery">Gallery</dt>
+ <dd><a href="@Href("~/Gallery/View", gallery.Id)" title="View @gallery.Name gallery">@gallery.Name</a></dd>
+ <dt class="tags">Tags</dt>
+ <dd class="tags">
+ <ul class="tags">
+ @if (tagList.Count == 0) {
+ <li>This photo has no tags.</li>
+ } else {
+ foreach (var t in tagList) {
+ <li class="tag"><a href="@Href("~/Tag/View", t.Tags_TagName)">@t.Tags_TagName</a></li>
+ }
+ }
+ </ul>
+ @if (WebSecurity.IsAuthenticated) {
+ <a href="@Href("~/Photo/EditTags", photoId)">edit tags</a>
+ }
+ </dd>
+ </dl>
+
+ <p>
+ <a class="download" href="@Href("~/Photo/Full", photoId)" title="Download: @(photo.FileTitle + photo.FileExtension)">Download full photo</a> (@(photo.FileSize / 1024) KB)
+ </p>
+</div>
+<div class="main">
+ <img class="large-photo" alt="@Html.AttributeEncode(photo.FileTitle)" src="@Href("~/Photo/Thumbnail", photo.Id, new { size="large" })" />
+
+ @switch ((int)comments.Count) {
+ case 0:
+ <h2>Nobody has commented on this photo</h2>
+ break;
+ case 1:
+ <h2>This photo has generated one comment.</h2>
+ break;
+ default:
+ <h2>This photo has generated @comments.Count comments.</h2>
+ break;
+ }
+
+ <ol class="comments">
+ @foreach (var comment in comments) {
+ <li>
+ <h3 class="comment-header">
+ <a href="@Href("~/User/View", comment.UserId)" title="View @(comment.DisplayName)'s profile">@comment.DisplayName</a> commented at @comment.CommentDate:
+ </h3>
+ <p class="comment-body">@comment.CommentText</p>
+ </li>
+ }
+ </ol>
+
+ @if (WebSecurity.IsAuthenticated) {
+ <form method="post" action="">
+ <fieldset id="addComment">
+ <legend>Post new comment</legend>
+ <ol>
+ <li>
+ <label for="newComment">Comment</label>
+ <textarea id="newComment" name="newComment" title="Your comment" rows="6" cols="70"></textarea>
+ </li>
+ </ol>
+ <p class="form-actions">
+ <input type="submit" title="Add comment" value="Add comment" />
+ </p>
+ </fieldset>
+ </form>
+ } else {
+ <p>
+ Only registered user may leave comments. Please <a href="@Href("~/Account/Login")">login</a>
+ or <a href="@Href("~/Account/Register")">create an account</a> to leave a comment.
+ </p>
+ }
+</div>
View
456 OrlandoCodeCamp/PhotoSharing-No-Payment/Styles/Site.css
@@ -0,0 +1,456 @@
+/* Reset default styles
+-------------------------------------------------------*/
+body {
+ background-color: #eaeeef;
+ margin: 0;
+ padding: 0;
+ font-family: "Segoe UI", Tahoma, Verdana, Arial, Sans-Serif;
+ color: #343434;
+ min-width: 960px;
+}
+
+a {
+ color: #1170a9;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #0d527b;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-weight: normal;
+}
+
+h1, h2, h3 {
+ margin: 0;
+ padding: 0;
+}
+
+h2 {
+ font-size: 1.2em;
+}
+
+h3 {
+ font-size: 1.1em;
+}
+
+p {
+ padding: 10px 0;
+ margin: 0;
+}
+
+dl {
+ margin: 0;
+}
+
+ dt {
+ font-weight: bold;
+ }
+
+ dt:after {
+ content: ":";
+ }
+
+ dd {
+ margin-left: 5px;
+ font-size: .85em;
+ margin-bottom: 5px;
+ }
+
+
+/* Basic Layout
+-------------------------------------------------------*/
+#banner {
+ padding: 20px 20px 0 20px;
+ height: 60px;
+ background: #eaeaea url("../Images/header-bkg.png") repeat-x left bottom;
+ font-family: Tahoma;
+ border-bottom: 1px solid #e0e0e0;
+
+ /*CSS3 properties*/
+ text-shadow: -1px 1px 1px #fff;
+}
+
+ .site-title {
+ margin: 0;
+ padding: 0;
+ font-size: 1.75em;
+ display: inline;
+ }
+
+ .site-title a {
+ color: #2f5163;
+ }
+
+#page {
+ padding: 20px 15px;
+}
+
+#footer {
+ clear: both;
+ border-top: 1px dotted #c7ccd3;
+ margin: 20px 0 20px 0;
+ padding: 20px 0 20px 0;
+ font-size: 0.8em;
+ text-align: center;
+ color: #343434;
+}
+
+
+ /* Menu
+ ----------*/
+ #menu {
+ padding: 0;
+ margin: 0 0 0 60px;
+ display: inline;
+ }
+
+ #menu li {
+ padding: 0;
+ margin: 0 24px 0 0;
+ display: inline;
+ }
+
+ #menu li a {
+ padding: 12px 12px 12px 40px;
+ color: #0F6395;
+ }
+
+ #menu li a:hover {
+ color: #09354f;
+ }
+
+ #menu li.galleries a {
+ background: url("../Images/icon-gallery.png") no-repeat 0 50%;
+ }
+
+ #menu li.tags a {
+ background: url("../Images/icon-tags.png") no-repeat 0 50%;
+ }
+
+ #menu li.account a {
+ background: url("../Images/icon-account.png") no-repeat 0 50%;
+ }
+
+ #menu li.login {
+ margin-left: 0;
+ font-size: .75em;
+ }
+
+ #menu li.login a {
+ padding: 0;
+ }
+
+ #menu li.login a:before {
+ content: "[";
+ padding-right: 3px;
+ }
+
+ #menu li.login a:after {
+ content: "]";
+ padding-left: 3px;
+ }
+
+/* Shared Layout
+-------------------------------------------------------*/
+div.sidebar {
+ float: left;
+ width: 30%;
+ margin-right: 30px;
+ height: 100%;
+
+ /*CSS3 properties*/
+ word-wrap: break-word;
+}
+
+div.main {
+ float: left;
+ width:65%;
+}
+
+/* Thumbnail Layout
+-------------------------------------------------------*/
+ul.thumbnails {
+ margin:0;
+ padding:0;
+}
+ul.thumbnails li {
+ position: relative;
+ list-style: none;
+ float: left;
+ margin: 8px;
+ padding: 5px;
+ font-size: small;
+ text-align: center;
+ border: 1px solid transparent;
+ width: 202px;
+ height: 202px;
+ line-height: 200px;
+ display: block;
+}
+
+ul.gallery li {
+ height: 220px;
+}
+
+ ul.thumbnails li span {
+ display: block;
+ }
+
+ ul.thumbnails li span.image-overlay {
+ display: none;
+ width: 200px;
+ padding: 5px;
+ background-color: #fff;
+ color: #343434;
+
+ /*CSS3 properties*/
+ border-radius: 7px 7px 0 0;
+ -moz-border-radius: 7px 7px 0 0;
+ -webkit-border-radius: 7px 7px 0 0;
+ background-color: rgba(255, 255, 255, 0.75);
+ word-wrap: break-word;
+ }
+
+ ul.thumbnails li span.below-image {
+ line-height: normal;
+ }
+
+ ul.thumbnails li img {
+ margin: auto;
+ display: inline;
+ vertical-align: middle;
+ }
+
+ul.thumbnails li:hover {
+ background: #f3f6f7;
+ border-color: #dbe2e5;
+
+ /*CSS3 properties*/
+ border-radius: 7px;
+ -moz-border-radius: 7px;
+ -webkit-border-radius: 7px;
+ box-shadow: 0px 0px 10px #d0d0d0;
+ -moz-box-shadow: 0px 0px 10px #d0d0d0;
+ -webkit-box-shadow: 0px 0px 10px #d0d0d0;
+}
+
+ ul.thumbnails li:hover span.image-overlay {
+ display: block;
+ position: absolute;
+ top: 0;
+ left: 0;
+ line-height: normal;
+ }
+
+/* Single Photo Layout
+--------------------------------------------------*/
+/* Sidebar
+-------------*/
+dd.tags {
+ margin: 5px;
+}
+
+ ul.tags {
+ list-style: none;
+ display: inline;
+ padding: 0;
+ margin: 0;
+ }
+
+ ul.tags li {
+ display:inline;
+ padding: 1px 5px;
+ color: #fff;
+ background-color: #757575;
+
+ /*CSS3 properties*/
+ border-radius: 3px;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ }
+
+ ul.tags li a {
+ color: #fff;
+ }
+
+ ul.tags li:hover {
+ background-color: #444;
+ }
+
+.download {
+ font-size: 1.1em;
+ padding-left: 20px;
+ background: url("../Images/download.png") no-repeat left;
+}
+
+/* Main
+----------*/
+ol.comments {
+ font-size: .85em;
+ padding: 0;
+ list-style: none;
+}
+
+ ol.comments h3 {
+ margin-top: 5px;
+ font-weight: bold;
+ border-bottom: 1px solid #dbe2e5;
+ }
+
+ ol.comments p {
+ padding: 0 0 0 5px;
+ }
+
+#addComment textarea {
+ width: 100%;
+}
+
+/* Forms
+----------------------------------------------------------*/
+fieldset {
+ margin: 1em 0;
+ padding: 1em;
+ border: 1px solid #ccc;
+}
+
+ fieldset legend {
+ font-size: 1.1em;
+ font-weight: bold;
+ padding: 2px 4px 8px 4px;
+ }
+
+ fieldset ol {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ }
+
+ fieldset ol li {
+ padding-bottom: 5px;
+ }
+
+ fieldset label {
+ display: block;
+ }
+
+ fieldset label.checkbox {
+ display: inline;
+ }
+
+ fieldset input[type="text"], input[type="password"] {
+ border: 1px solid #ccc;
+ padding: 2px;
+ font-size: 1.2em;
+ color: #444;
+ width: 300px;
+ }
+
+ fieldset input[type="submit"] {
+ padding: 5px;
+ }
+
+ fieldset textarea {
+ color: #444;
+ width: 300px;
+ }
+
+ .no-legend {
+ border: none;
+ padding: 0;
+ }
+
+ .no-legend legend {
+ display: none;
+ }
+
+fieldset input[type="text"].input-validation-error,
+input[type="password"].input-validation-error,
+.input-validation-error {
+ border: 1px solid #be3e16;
+ background-color: #ffe4e4;
+}
+
+.field-validation-error {
+ display: block;
+ color: #be3e16;
+ font-weight: bold;
+}
+
+.validation-summary-errors {
+ color: #be3e16;
+ font-weight: bold;
+}
+
+.validation-summary-errors ul {
+ list-style: none;
+ padding: 0;
+ margin: 0
+}
+
+/* Misc
+----------------------------------------------------------*/
+.similar-tags {
+ clear: both;
+ font-weight: bold;
+ margin: 5px;
+}
+
+.user-photos {
+ padding: 0;
+ margin: 0;
+}
+
+.confirm-removal {
+ color: #d63301;
+}
+
+ .large-photo {
+ margin: 10px 0;
+ }
+
+.thumbnail-border, .large-photo {
+ border: 1px solid #dbe2e5;
+ display: block;
+}
+
+.thumbnail-no-border {
+ border: none;
+ display: block;
+}
+
+#file-upload-buttons input[type=submit] {
+ display: block;
+ font-size: 1.2em;
+ padding: 5px;
+}
+
+.actions {
+ clear: both;
+}
+
+.message {
+ clear: both;
+ border: 1px solid;
+ margin: 10px 0px;
+ padding: 15px 15px;
+
+ /*CSS3 properties*/
+ border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ box-shadow: 2px 2px 5px #888;
+ -webkit-box-shadow: 2px 2px 5px #888;
+ -moz-box-shadow: 2px 2px 5px #888;
+}
+
+.info {
+ background: #bde5f8;
+ color: #00529b;
+}
+
+.error {
+ background: #ffe4e4;
+ color: #be3e16;
+}
View
30 OrlandoCodeCamp/PhotoSharing-No-Payment/Tag/Default.cshtml
@@ -0,0 +1,30 @@
+@{
+ Page.Title = "View All Tags";
+
+ var db = Database.Open("PhotoGallery");
+
+ var tags = db.Query(@"SELECT Tags_TagName AS TagName, COUNT(*) AS TagCount
+ FROM Photos_Tags
+ GROUP BY Tags_TagName
+ ORDER BY Tags_TagName").ToList();
+}
+
+<h1>Tags</h1>
+
+@if (tags.Count == 1) {
+ <p>There is one tag.</p>
+} else {
+ <p>There are @tags.Count tags.</p>
+}
+
+<ul class="thumbnails gallery">
+ @foreach (var tag in tags) {
+ <li class="tag">
+ <a href="@Href("~/Tag/View", tag.TagName)">
+ <img alt="Images from @tag.TagName" src="@Href("~/Tag/Thumbnail", tag.TagName)" class="thumbnail-no-border" />
+ <span class="below-image">@tag.TagName</span>
+ <span class="image-overlay">@tag.TagCount photo(s)</span>
+ </a>
+ </li>
+ }
+</ul>
View
33 OrlandoCodeCamp/PhotoSharing-No-Payment/Tag/Thumbnail.cshtml
@@ -0,0 +1,33 @@
+@{
+ // Cache the image for a minute
+ Response.OutputCache(60);
+
+ var tagName = UrlData[0];
+
+ var db = Database.Open("PhotoGallery");
+ var tag = db.Query("SELECT TagName FROM Tags WHERE TagName = @0", tagName);
+ var photoList = db.Query(@"SELECT TOP(3) Photos.FileContents
+ FROM Photos, Photos_Tags
+ WHERE Photos.Id = Photos_Tags.Photos_Id AND Photos_Tags.Tags_TagName = @0", tagName).Shuffle().ToList();
+
+ if (tag != null && photoList.Count > 0) {
+ using (MultiThumbnailGenerator generator = new MultiThumbnailGenerator()) {
+ foreach (var photo in photoList) {
+ using (var imageStream = new System.IO.MemoryStream(photo.FileContents)) {
+ using (var image = System.Drawing.Image.FromStream(imageStream)) {
+ generator.AddImage(image);
+ }
+ }
+ }
+
+ using (var outStream = new System.IO.MemoryStream()) {
+ generator.WritePngToStream(outStream);
+ var image = new WebImage(outStream);
+ image.Write();
+ }
+ }
+ } else {
+ // no photos - hopefully user will never see this
+ Response.Redirect("~/Shared/gallery-empty.png");
+ }
+}
View
45 OrlandoCodeCamp/PhotoSharing-No-Payment/Tag/View.cshtml
@@ -0,0 +1,45 @@
+@{
+ var tagName = UrlData[0];
+ Page.Title = "View Tag - " + tagName;
+
+ var db = Database.Open("PhotoGallery");
+ var photos = db.Query(@"SELECT Photos.Id, Photos.FileTitle
+ FROM Photos, Photos_Tags
+ WHERE Photos.Id = Photos_Tags.Photos_Id AND Photos_Tags.Tags_TagName = @0", tagName).ToList();
+ var similarTags = db.Query(@"SELECT Tags_TagName AS TagName, COUNT(*) AS Count
+ FROM Photos_Tags WHERE Photos_Id IN (SELECT Photos_Id FROM Photos_Tags WHERE Tags_TagName = @0) AND Tags_TagName != @0
+ GROUP BY Tags_TagName
+ ORDER BY Count DESC", tagName).ToList();
+}
+
+<h1>@tagName</h1>
+
+@if (photos.Count == 0) {
+ <p>There are no photos with this tag.</p>
+} else {
+ if (photos.Count == 1) {
+ <p>There is one photo with this tag.</p>
+ } else {
+ <p>There are @photos.Count photos with this tag.</p>
+ }
+
+ <ul class="thumbnails">
+ @foreach (var photo in photos) {
+ <li>
+ <a href="@Href("~/Photo/View", photo.Id)">
+ <img alt="thumbnail of @Path.GetFileNameWithoutExtension(photo.FileTitle)" src="@Href("~/Photo/Thumbnail", photo.Id)" class="thumbnail-border" />
+ <span class="image-overlay">@Path.GetFileNameWithoutExtension(photo.FileTitle)</span>
+ </a>
+ </li>
+ }
+ </ul>
+
+ if (similarTags.Count > 0) {
+ <h2 class="similar-tags">Similar tags:</h2>
+ <ul class="tags">
+ @foreach (var t in similarTags) {
+ <li class="tag"><a href="@Href("~/Tag/View", t.TagName)">@t.TagName</a></li>
+ }
+ </ul>
+ }
+}
View
48 OrlandoCodeCamp/PhotoSharing-No-Payment/User/Default.cshtml
@@ -0,0 +1,48 @@
+@{
+ WebSecurity.RequireAuthenticatedUser();
+
+ var db = Database.Open("PhotoGallery");
+
+ var user = db.QuerySingle("SELECT UserId, DisplayName, Bio FROM UserProfiles WHERE UserId = @0", WebSecurity.CurrentUserId);
+
+ Page.Title = "Edit Profile - " + user.DisplayName;
+
+ string displayName = null;
+ if (IsPost) {
+ displayName = Request["displayName"].Trim();
+ if (displayName.IsEmpty()) {
+ displayName = User.Identity.Name;
+ }
+ var bio = Request["bio"].Trim();
+
+ db.Execute("UPDATE UserProfiles SET DisplayName = @0, Bio = @1 WHERE UserId = @2", displayName, bio, WebSecurity.CurrentUserId);
+
+ Response.Redirect(Href("~/User/View",user.UserId));
+ }
+}
+
+<h1>Edit Profile</h1>
+
+<p>
+ Welcome back, @user.DisplayName. You may use the below form to change your display name (shown in comments)
+ and biography (shown on your <a href="@Href("~/User/View", WebSecurity.CurrentUserId)">public profile</a>).
+</p>
+
+<form method="post" action="">
+ <fieldset class="no-legend">
+ <legend>Edit Profile</legend>
+ <ol>
+ <li>
+ <label for="displayName">Display name:</label>
+ <input type="text" id="displayName" name="displayName" title="Change display name" placeholder="Display name" value="@(displayName ?? user.DisplayName)" />
+ </li>
+ <li>
+ <label for="bio">Bio:</label>
+ <textarea type="text" id="bio" name="bio" title="Change bio" rows="4" cols="50" placeholder="Biography">@user.Bio</textarea>
+ </li>
+ </ol>
+ <p class="form-actions">
+ <input type="submit" value="Save" title="Save Changes" />
+ </p>
+ </fieldset>
+</form>
View
53 OrlandoCodeCamp/PhotoSharing-No-Payment/User/View.cshtml
@@ -0,0 +1,53 @@
+@{
+ var db = Database.Open("PhotoGallery");
+
+ var id = UrlData[0].AsInt();
+ var user = db.QuerySingle("SELECT UserId, DisplayName, Bio FROM UserProfiles WHERE UserId = @0", id);
+ if (user == null) {
+ Response.SetStatus(HttpStatusCode.NotFound);
+ return;
+ }
+
+ Page.Title = "User - " + user.DisplayName;
+
+ var photos = db.Query("SELECT Id, FileTitle FROM Photos WHERE UserId = @0 ORDER BY FileTitle", id).ToList();
+}
+
+<div class="sidebar">
+ <dl>
+ <dt>Display name</dt>
+ <dd>@user.DisplayName</dd>
+ <dt>Bio</dt>
+ <dd>
+ @if (user.Bio != "") {
+ <text>@user.Bio</text>
+ } else {
+ <text>This user has not created a biography.</text>
+ }
+ </dd>
+ </dl>
+ @if (WebSecurity.CurrentUserId == user.UserId) {
+ <p>
+ You can <a href="@Href("~/User")">edit your profile</a> if you desire.
+ </p>
+ }
+</div>
+<div class="main">
+<h1>@(user.DisplayName)'s Photos</h1>
+ @if (photos.Count == 1) {
+ <h2>This user has uploaded one photo.</h2>
+ } else {
+ <h2>This user has uploaded @photos.Count photos.</h2>
+ }
+
+ <ul class="thumbnails user-photos">
+ @foreach (var photo in photos) {
+ <li>
+ <a href="@Href("~/Photo/View", photo.Id)">
+ <img alt="thumbnail of @Path.GetFileNameWithoutExtension(photo.FileTitle)" src="@Href("~/Photo/Thumbnail", photo.Id)" class="thumbnail-border" />
+ <span class="image-overlay">@Path.GetFileNameWithoutExtension(photo.FileTitle)</span>
+ </a>
+ </li>
+ }
+ </ul>
+</div>
View
3 OrlandoCodeCamp/PhotoSharing-No-Payment/_AppStart.cshtml
@@ -0,0 +1,3 @@
+@{
+ WebSecurity.InitializeDatabaseConnection("PhotoGallery", "UserProfiles", "UserId", "Email", true);
+}
View
4 OrlandoCodeCamp/PhotoSharing-No-Payment/_PageStart.cshtml
@@ -0,0 +1,4 @@
+@{
+ // Set the layout page for the whole site
+ Layout = "_SiteLayout.cshtml";
+}
View
33 OrlandoCodeCamp/PhotoSharing-No-Payment/_SiteLayout.cshtml
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8" />
+ <title>@Page.Title</title>
+ <link href="@Href("~/Styles/Site.css")" rel="stylesheet" />
+ <link href="@Href("~/favicon.ico")" rel="shortcut icon" type="image/x-icon" />
+ </head>
+ <body>
+ <div id="banner">
+ <p class="site-title"><a href="@Href("~/")">Photo Gallery</a></p>
+ <ul id="menu">
+ <li class="galleries"><a href="@Href("~/Gallery")">Galleries</a></li>
+ <li class="tags"><a href="@Href("~/Tag")">Tags</a></li>
+ <li class="account"><a href="@Href("~/User")">Account</a></li>
+ <li class="login">
+ @if (WebSecurity.IsAuthenticated) {
+ <text>Welcome <strong>@WebSecurity.CurrentUserName</strong>!
+ <a href="@Href("~/Account/Logout")">Logout</a></text>
+ } else {
+ <text><a href="@Href("~/Account/Login")">Login</a></text>
+ }
+ </li>
+ </ul>
+ </div>
+ <div id="page">
+ @RenderBody()
+ </div>
+ <div id="footer">
+ &copy; @DateTime.Now.Year - Photo Gallery
+ </div>
+ </body>
+</html>
View
BIN OrlandoCodeCamp/PhotoSharing-No-Payment/bin/Microsoft.Web.Helpers.dll
Binary file not shown.
View
BIN OrlandoCodeCamp/PhotoSharing-No-Payment/favicon.ico
Binary file not shown.
View
2 OrlandoCodeCamp/PhotoSharing-No-Payment/robots.txt
@@ -0,0 +1,2 @@
+
+# WebMatrix 1.0

0 comments on commit 49aa245

Please sign in to comment.
Something went wrong with that request. Please try again.