PageRenderTime 24ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/Mindfor.WebMP/CmsController.cs

http://webmp.codeplex.com
C# | 493 lines | 295 code | 58 blank | 140 comment | 49 complexity | edc69622c343cd853cc34643a7a02c3d MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Drawing.Imaging;
  5. using System.Globalization;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Net.Mail;
  9. using System.Text;
  10. using System.Web;
  11. using System.Web.Mvc;
  12. using System.Web.Routing;
  13. using System.Xml.Linq;
  14. using FreeImageAPI;
  15. using Mindfor.Web.Config;
  16. using Mindfor.Web.Data;
  17. using NHibernate;
  18. using NHibernate.Linq;
  19. using Mindfor.Web.Models;
  20. using System.ComponentModel;
  21. using System.Linq.Expressions;
  22. namespace Mindfor.Web
  23. {
  24. /// <summary>
  25. /// Base CMS controller which implements cms options loading, such as configuration and data provider.
  26. /// </summary>
  27. public abstract class CmsController : Controller
  28. {
  29. ISession m_data;
  30. Uri m_siteUri;
  31. SmtpClient m_smtp;
  32. /// <summary>
  33. /// Gets data session.
  34. /// </summary>
  35. public ISession Data
  36. {
  37. get
  38. {
  39. if (m_data == null)
  40. {
  41. m_data = CmsApplication.DataProvider.GetCurrentSession();
  42. if (m_data == null)
  43. throw new InvalidOperationException("Can not get current data session.");
  44. }
  45. return m_data;
  46. }
  47. }
  48. /// <summary>
  49. /// Gets whether running in debug mode.
  50. /// </summary>
  51. public bool IsDebug
  52. {
  53. get
  54. {
  55. #if DEBUG
  56. return true;
  57. #else
  58. return false;
  59. #endif
  60. }
  61. }
  62. /// <summary>
  63. /// Gets site url that is determined from current request.
  64. /// </summary>
  65. public Uri SiteUrl
  66. {
  67. get
  68. {
  69. if (m_siteUri == null)
  70. {
  71. Uri requestUrl = this.Request.Url;
  72. string siteUrl = requestUrl.AbsoluteUri.Substring(0,
  73. requestUrl.AbsoluteUri.Length - requestUrl.PathAndQuery.Length);
  74. m_siteUri = new Uri(siteUrl, UriKind.Absolute);
  75. }
  76. return m_siteUri;
  77. }
  78. }
  79. /// <summary>
  80. /// Gets controller module.
  81. /// </summary>
  82. public ModuleBase Module { get; private set; }
  83. /// <summary>
  84. /// Gets current authenticated user. Returns null if user is anonymous.
  85. /// </summary>
  86. public new User User { get; private set; }
  87. /// <summary>
  88. /// Gets current request language.
  89. /// </summary>
  90. public Language Language { get; private set; }
  91. /// <summary>
  92. /// Gets whether user is authenticated.
  93. /// </summary>
  94. public bool IsAuthenticated
  95. {
  96. get { return this.User != null; }
  97. }
  98. #region For page module
  99. /// <summary>
  100. /// Gets current request page.
  101. /// </summary>
  102. public Page CurrentPage
  103. {
  104. get { return ViewData["Global.CurrentPage"] as Page; }
  105. }
  106. /// <summary>
  107. /// Gets current page text.
  108. /// </summary>
  109. public PageText CurrentPageText
  110. {
  111. get { return ViewData["Global.CurrentPageText"] as PageText; }
  112. }
  113. /// <summary>
  114. /// Gets main action name if current action is sub-action.
  115. /// If current action is main action then returns null.
  116. /// </summary>
  117. public string MainActionName
  118. {
  119. get { return ViewData["Global.MainActionName"] as string; }
  120. }
  121. /// <summary>
  122. /// Gets whether current action is main- or sub-.
  123. /// If false, then CurrentPage and CurrentPageText is taken from main action.
  124. /// </summary>
  125. public bool IsMainAction
  126. {
  127. get { return MainActionName == null; }
  128. }
  129. /// <summary>
  130. /// Gets page title.
  131. /// </summary>
  132. public PageTitleCollection PageTitle { get; private set; }
  133. #endregion
  134. /// <summary>
  135. /// Initializes new instance.
  136. /// </summary>
  137. public CmsController()
  138. {
  139. }
  140. /// <summary>
  141. /// Initializes class before invoke action.
  142. /// </summary>
  143. /// <param name="requestContext">Request context.</param>
  144. protected override void Initialize(RequestContext requestContext)
  145. {
  146. // base initialize
  147. base.Initialize(requestContext);
  148. // get module
  149. string moduleName = requestContext.RouteData.Values["module"] as string;
  150. if (moduleName != null)
  151. {
  152. Module = ModuleFactory.Default.Modules[moduleName];
  153. HttpContext.Items["module"] = Module;
  154. }
  155. // get current user
  156. if (base.User != null && base.User.Identity != null &&
  157. base.User.Identity.IsAuthenticated)
  158. User = Data.Query<User>().GetUser(base.User.Identity.Name);
  159. // get current language and culture
  160. string langUrlName = (string)requestContext.RouteData.Values["lang"];
  161. if (String.IsNullOrEmpty(langUrlName))
  162. langUrlName = CmsConfig.Default.DefaultLanguage;
  163. if (!String.IsNullOrEmpty(langUrlName))
  164. Language = Data.Query<Language>().FirstOrDefault(r => r.UrlName == langUrlName);
  165. if (Language == null)
  166. Language = Data.Query<Language>().FirstOrDefault();
  167. if (Language != null)
  168. {
  169. CultureInfo culture = null;
  170. try
  171. {
  172. culture = CultureInfo.GetCultureInfo(Language.Culture);
  173. }
  174. catch (Exception ex)
  175. {
  176. throw new InvalidOperationException("Cannot find \"" + Language.Culture + "\" culture.", ex);
  177. }
  178. System.Threading.Thread.CurrentThread.CurrentCulture = culture;
  179. System.Threading.Thread.CurrentThread.CurrentUICulture = culture;
  180. }
  181. ControllerContext.HttpContext.Trace.Write("CmsController", "Initialize end");
  182. }
  183. /// <summary>
  184. /// Adds error to local log and mindfor server log.
  185. /// </summary>
  186. /// <param name="ex">Error to add to logs.</param>
  187. protected void LogError(Exception ex)
  188. {
  189. // log local
  190. try
  191. {
  192. Log log = new Log(ex);
  193. using (ITransaction t = Data.BeginTransaction())
  194. {
  195. Data.Save(log);
  196. t.Commit();
  197. }
  198. }
  199. catch { }
  200. // log to server
  201. if (CmsConfig.Default.ApplicationId.HasValue)
  202. Mindfor.Error.ErrorProxy.SubmitSafe(CmsConfig.Default.ApplicationId.Value, ex);
  203. }
  204. /// <summary>
  205. /// Sets model complex property to value that was loaded from DataProvider by primary key
  206. /// specified in value provider.
  207. /// </summary>
  208. /// <param name="model">Model to update.</param>
  209. /// <param name="propertyName">Complex property that references another type.</param>
  210. /// <param name="primaryKeyName">Primary key name in complex property.</param>
  211. /// <exception cref="TypeLoadException">Occures when complex property is not found.</exception>
  212. protected void UpdateModelReference(object model, string propertyName, string primaryKeyName)
  213. {
  214. if (String.IsNullOrEmpty(propertyName))
  215. throw new ArgumentNullException(propertyName);
  216. if (String.IsNullOrEmpty(primaryKeyName))
  217. throw new ArgumentNullException(primaryKeyName);
  218. // find properties
  219. PropertyDescriptor propDescriptor = TypeDescriptor.GetProperties(model)[propertyName];
  220. if (propDescriptor == null)
  221. throw new TypeLoadException(String.Format("Can not find property \"{0}\".", propertyName));
  222. PropertyDescriptor primaryPropDescriptor = TypeDescriptor.GetProperties(propDescriptor.PropertyType)[primaryKeyName];
  223. if (primaryPropDescriptor == null)
  224. throw new TypeLoadException(String.Format("Can not find property \"{0}\".", primaryKeyName));
  225. // get complex property value
  226. string key = propertyName + "." + primaryKeyName;
  227. ValueProviderResult valueProviderResult = ValueProvider.GetValue(key);
  228. if (valueProviderResult != null)
  229. {
  230. object id = valueProviderResult.ConvertTo(primaryPropDescriptor.PropertyType);
  231. if (id != null)
  232. {
  233. object reference = Data.Get(propDescriptor.PropertyType, id);
  234. propDescriptor.SetValue(model, reference);
  235. }
  236. }
  237. }
  238. /// <summary>
  239. /// Sets model complex property to value that was loaded from DataProvider by primary key
  240. /// specified in value provider.
  241. /// </summary>
  242. /// <param name="model">Model to update.</param>
  243. /// <param name="propertyExpression">Lambda expression to complex property that references another type.</param>
  244. /// <param name="primaryKeyExpression">Lambda expression to primary key in complex property.</param>
  245. /// <exception cref="TypeLoadException">Occures when complex property is not found.</exception>
  246. protected void UpdateModelReference<TModel, TProperty, TKey>(TModel model, Expression<Func<TModel, TProperty>> propertyExpression, Expression<Func<TProperty, TKey>> primaryKeyExpression)
  247. {
  248. string propertyName = ExpressionHelper.GetExpressionText(propertyExpression);
  249. string primaryKeyName = ExpressionHelper.GetExpressionText(primaryKeyExpression);
  250. UpdateModelReference(model, propertyName, primaryKeyName);
  251. }
  252. /// <summary>
  253. /// Sets model complex property to value that was loaded from DataProvider by primary key "Id".
  254. /// </summary>
  255. /// <param name="model">Model to update.</param>
  256. /// <param name="propertyExpression">Lambda expression to complex property that references another type.</param>
  257. /// <exception cref="TypeLoadException">Occures when complex property is not found.</exception>
  258. protected void UpdateModelReference<TModel, TProperty>(TModel model, Expression<Func<TModel, TProperty>> propertyExpression)
  259. {
  260. string propertyName = ExpressionHelper.GetExpressionText(propertyExpression);
  261. UpdateModelReference(model, propertyName, "Id");
  262. }
  263. #region Custom ActionResults
  264. /// <summary>
  265. /// Returns <see cref="FileContentResult"/> which sends image to response.
  266. /// </summary>
  267. /// <param name="image">Image to send to response.</param>
  268. protected virtual FileResult Image(Image image)
  269. {
  270. return Image(image, null, -1, -1);
  271. }
  272. /// <summary>
  273. /// Returns <see cref="FileStreamResult"/> with xml document data.
  274. /// </summary>
  275. /// <param name="xmlDocument">Xml document to render.</param>
  276. protected virtual XResult Xml(XDocument xmlDocument)
  277. {
  278. return new XResult(xmlDocument);
  279. }
  280. /// <summary>
  281. /// Returns <see cref="FileStreamResult"/> with xml document data.
  282. /// </summary>
  283. /// <param name="rootElement">Xml root element.</param>
  284. protected virtual XResult Xml(XElement rootElement)
  285. {
  286. return new XResult(rootElement);
  287. }
  288. /// <summary>
  289. /// Returns <see cref="FileContentResult"/>, which sends image to response.
  290. /// Image size changes proportional.
  291. /// </summary>
  292. /// <param name="image">Image to send to response.</param>
  293. /// <param name="name">Image file name.</param>
  294. /// <param name="maxWidth">Max width of image. Use -1 not to analyse width.</param>
  295. /// <param name="maxHeight">Max height of image. Use -1 not to analyse height.</param>
  296. protected virtual FileResult Image(Image image, string name, int maxWidth, int maxHeight)
  297. {
  298. if (image == null)
  299. return null;
  300. const int maxOriginalArea = 100 * 100;
  301. const int outputImageQuality = 80;
  302. Image sizedImage;
  303. // Send the image to the user
  304. if (image.RawFormat.Guid == ImageFormat.Gif.Guid)
  305. {
  306. // Save the gif (but we can't ajust it's size or DPI, sorry)
  307. sizedImage = image.AdjustGifImage(maxWidth, maxHeight);
  308. }
  309. else
  310. {
  311. // Ajust and save image
  312. sizedImage = image.AdjustImage(maxWidth, maxHeight, -1);
  313. }
  314. // Set expiration and ETag
  315. HttpCachePolicyBase cache = HttpContext.Response.Cache;
  316. TimeSpan expireTs = TimeSpan.FromDays(7);
  317. cache.SetCacheability(HttpCacheability.Private);
  318. cache.SetETag(Language.Name + "_" + name + "_" + maxWidth + "_" + maxHeight);
  319. cache.SetExpires(DateTime.Now.Add(expireTs));
  320. cache.SetMaxAge(expireTs);
  321. // Check area
  322. if (sizedImage.Width * sizedImage.Height > maxOriginalArea)
  323. {
  324. Stream sizedImageStream = new MemoryStream();
  325. sizedImage.Save(sizedImageStream, ImageFormat.Png);
  326. sizedImageStream.Seek(0, SeekOrigin.Begin);
  327. FREE_IMAGE_FORMAT fiFormat = FREE_IMAGE_FORMAT.FIF_PNG;
  328. // Save to progressive jpeg
  329. FIBITMAP dib = new FIBITMAP();
  330. if (!dib.IsNull)
  331. FreeImage.Unload(dib);
  332. try
  333. {
  334. dib = FreeImage.LoadFromStream(sizedImageStream, FREE_IMAGE_LOAD_FLAGS.PNG_IGNOREGAMMA, ref fiFormat);
  335. }
  336. catch (BadImageFormatException exx)
  337. {
  338. throw new Exception("?????????! :( " + fiFormat.ToString(), exx);
  339. }
  340. if (!dib.IsNull)
  341. {
  342. Stream progressiveStream = new MemoryStream();
  343. if (FreeImage.SaveToStream(dib, progressiveStream, FREE_IMAGE_FORMAT.FIF_JPEG, FREE_IMAGE_SAVE_FLAGS.JPEG_PROGRESSIVE | FREE_IMAGE_SAVE_FLAGS.JPEG_QUALITYSUPERB))
  344. {
  345. // The bitmap was saved to stream but is still allocated in memory, so the handle has to be freed.
  346. if (!dib.IsNull)
  347. FreeImage.Unload(dib);
  348. // Make sure to set the handle to null so that it is clear that the handle is not pointing to a bitmap.
  349. dib.SetNull();
  350. progressiveStream.Seek(0, SeekOrigin.Begin);
  351. return File(progressiveStream, "image/jpeg", name);
  352. }
  353. }
  354. }
  355. // ELSE
  356. // Return image as png or jpeg
  357. if (image.RawFormat.Guid == ImageFormat.Gif.Guid
  358. || image.RawFormat.Guid == ImageFormat.Png.Guid)
  359. {
  360. byte[] bytes = sizedImage.SaveImage(ImageFormat.Png, outputImageQuality);
  361. return File(bytes, "image/png", name);
  362. }
  363. else
  364. {
  365. byte[] bytes = sizedImage.SaveImage(System.Drawing.Imaging.ImageFormat.Jpeg, outputImageQuality);
  366. return File(bytes, "image/jpeg", name);
  367. }
  368. }
  369. /// <summary>
  370. /// Returns <see cref="MessageResult"/> which renders view "Message".
  371. /// ViewData "Message" parameter is set.
  372. /// </summary>
  373. /// <param name="message">Message to show.</param>
  374. /// <param name="links">Additional links to show to user.</param>
  375. /// <returns>ViewResult which renders view "Message".</returns>
  376. protected virtual MessageResult Message(string message, params Link[] links)
  377. {
  378. return new MessageResult(message, links)
  379. {
  380. ViewData = this.ViewData,
  381. TempData = this.TempData
  382. };
  383. }
  384. /// <summary>
  385. /// Returns <see cref="MessageResult"/> which renders view "Message".
  386. /// ViewData "Message" parameter is set.
  387. /// </summary>
  388. /// <param name="message">Message to show.</param>
  389. /// <param name="autoRedirectUrl">Auto redirect url. If <c>Null</c> then auto redirect is disabled.</param>
  390. /// <param name="links">Additional links to show to user.</param>
  391. /// <returns>ViewResult which renders view "Message".</returns>
  392. protected virtual MessageResult Message(string message, string autoRedirectUrl, params Link[] links)
  393. {
  394. return new MessageResult(message, links)
  395. {
  396. ViewData = this.ViewData,
  397. TempData = this.TempData,
  398. AutoRedirectUrl = autoRedirectUrl
  399. };
  400. }
  401. /// <summary>
  402. /// Returns <see cref="HttpStatusCodeResult"/> with status code 401 if unauthorized and 403 if authorized.
  403. /// </summary>
  404. /// <param name="statusDescription">The status description.</param>
  405. protected virtual HttpStatusCodeResult HttpAccessDenied(string statusDescription = null)
  406. {
  407. int code = User == null ? 401 : 403;
  408. return new HttpStatusCodeResult(code, statusDescription);
  409. }
  410. /// <summary>
  411. /// Returns RedirectResult which redirects to referrer uri.
  412. /// </summary>
  413. /// <param name="defaultUrl">Default url to redirect to if referer is null.</param>
  414. protected RedirectResult RedirectToReferrer(string defaultUrl = "/")
  415. {
  416. Uri uri = Request.UrlReferrer;
  417. return Redirect(uri == null ? defaultUrl : uri.ToString());
  418. }
  419. /// <summary>
  420. /// Returns RedirectResult which redirects to ReturnUrl from request.
  421. /// If one is null then returns default url redirect.
  422. /// </summary>
  423. /// <param name="defaultUrl">Default url to redirect to if referer is null.</param>
  424. protected virtual RedirectResult RedirectToReturnUrl(string defaultUrl)
  425. {
  426. string returnUrl = ViewData["returnUrl"] as string;
  427. if (String.IsNullOrEmpty(returnUrl))
  428. returnUrl = Request["returnUrl"];
  429. if (String.IsNullOrEmpty(returnUrl))
  430. returnUrl = defaultUrl;
  431. return Redirect(returnUrl);
  432. }
  433. #endregion
  434. }
  435. }