using System; using System.Collections.Generic; using System.Linq; using System.Text; using ScrewTurn.Wiki.PluginFramework; using System.Text.RegularExpressions; using System.Reflection; using System.IO; namespace ScrewTurn.Wiki.Plugins.RatingManagerPlugin { /// /// A plugin for assigning a rating to pages. /// public class RatingManager : IFormatterProviderV30 { const string defaultDirectoryName = "/__RatingManagerPlugin/"; const string cssFileName = "RatingManagerPluginCss.css"; const string jsFileName = "RatingManagerPluginJs.js"; const string starImageFileName = "RatingManagerPluginStarImage.gif"; const string ratingFileName = "RatingManagerPluginRatingFile.dat"; private IHostV30 _host; private bool _enableLogging = true; private static readonly ComponentInformation Info = new ComponentInformation("Rating Manager Plugin", "Threeplicate Srl", "3.0.3.555", "http://www.screwturn.eu", "http://www.screwturn.eu/Version/PluginPack/RatingManager2.txt"); private bool foundRatings = false; private static readonly Regex VotesRegex = new Regex(@"{rating(\|(.+?))?}", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); /// /// Initializes a new instance of the class. /// public RatingManager() { } /// /// Specifies whether or not to execute Phase 1. /// public bool PerformPhase1 { get { return false; } } /// /// Specifies whether or not to execute Phase 2. /// public bool PerformPhase2 { get { return false; } } /// /// Specifies whether or not to execute Phase 3. /// public bool PerformPhase3 { get { return true; } } /// /// Gets the execution priority of the provider (0 lowest, 100 highest). /// public int ExecutionPriority { get { return 50; } } /// /// Performs a Formatting phase. /// /// The raw content to Format. /// The Context information. /// The Phase. /// The Formatted content. public string Format(string raw, ContextInformation context, FormattingPhase phase) { // {rating} // _backendpage not found -> ignored StringBuilder buffer = new StringBuilder(raw); try { if(context.Context == FormattingContext.PageContent && context.Page != null) { if(context.HttpContext.Request["vote"] != null) { AddRating(context.Page.FullName, int.Parse(context.HttpContext.Request["vote"])); System.Web.HttpCookie cookie = new System.Web.HttpCookie("RatingManagerPlugin_" + context.Page.FullName, context.HttpContext.Request["vote"]); cookie.Expires = DateTime.Now.AddYears(10); context.HttpContext.Response.Cookies.Add(cookie); return ""; } } if(context.Page != null) { ComputeRating(context, buffer, context.Page.FullName); } else { return raw; } } catch(Exception ex) { LogWarning(string.Format("Exception occurred: {0}", ex.StackTrace)); } if(foundRatings) { buffer.Append(@""); buffer.Append(@""); buffer.Append(@""); foundRatings = false; } return buffer.ToString(); } /// /// Gets the rating of the plugin from the backendpage and display it to the user. /// /// The context. /// The page content. /// Full name of the page. private void ComputeRating(ContextInformation context, StringBuilder buffer, string fullPageName) { KeyValuePair block = FindAndRemoveFirstOccurrence(buffer); int numRatings = 0; while(block.Key != -1) { foundRatings = true; numRatings++; string result = null; if(block.Value.Groups[2].Value != "") { int average = (int)Math.Round((decimal)GetCurrentAverage(block.Value.Groups[2].Value), 0, MidpointRounding.AwayFromZero); result += @""; result += @""; } else if(context.HttpContext.Request.Cookies.Get("RatingManagerPlugin_" + fullPageName) != null) { int average = (int)Math.Round((decimal)GetCurrentAverage(fullPageName), 0, MidpointRounding.AwayFromZero); result += @""; result += @""; } else { int average = (int)Math.Round((decimal)GetCurrentAverage(fullPageName), 0, MidpointRounding.AwayFromZero); result += @" "; result += @""; } result += @""; buffer.Insert(block.Key, result); block = FindAndRemoveFirstOccurrence(buffer); } } private float GetCurrentAverage(string fullPageName) { float average = 0; try { IFilesStorageProviderV30 filesStorageProvider = GetDefaultFilesStorageProvider(); MemoryStream stream = new MemoryStream(); string fileContent = ""; if(FileExists(filesStorageProvider, defaultDirectoryName, ratingFileName)) { filesStorageProvider.RetrieveFile(defaultDirectoryName + ratingFileName, stream, true); stream.Seek(0, SeekOrigin.Begin); fileContent = Encoding.UTF8.GetString(stream.ToArray()); } string[] plugins = fileContent.Split(new String[] { "||" }, StringSplitOptions.RemoveEmptyEntries); // If the plugin is found return the posizion in the plugins array // otherwise return -1 int pluginIndex = SearchPlugin(plugins, fullPageName); if(pluginIndex != -1) { string[] pluginDetails = plugins[pluginIndex].Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries); average = (float)int.Parse(pluginDetails[2]) / (float)100; } } catch(Exception ex) { LogWarning(String.Format("Exception occurred {0}", ex.StackTrace)); } return average; } private void AddRating(string fullPageName, int rate) { IFilesStorageProviderV30 filesStorageProvider = GetDefaultFilesStorageProvider(); MemoryStream stream = new MemoryStream(); if(FileExists(filesStorageProvider, defaultDirectoryName, ratingFileName)) { filesStorageProvider.RetrieveFile(defaultDirectoryName + ratingFileName, stream, true); stream.Seek(0, SeekOrigin.Begin); } string fileContent = Encoding.UTF8.GetString(stream.ToArray()); string[] plugins = fileContent.Split(new String[] { "||" }, StringSplitOptions.RemoveEmptyEntries); StringBuilder sb = new StringBuilder(); // If the plugin is found return the posizion in the plugins array // otherwise return -1 int pluginIndex = SearchPlugin(plugins, fullPageName); if(pluginIndex != -1) { int numRates = int.Parse(plugins[pluginIndex].Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries)[1]); int average = int.Parse(plugins[pluginIndex].Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries)[2]); int newAverage = ((average * numRates) + (rate * 100)) / (numRates + 1); numRates++; plugins[pluginIndex] = fullPageName + "|" + numRates + "|" + newAverage; foreach(string plugin in plugins) { sb.Append(plugin + "||"); } } else { foreach(string plugin in plugins) { sb.Append(plugin + "||"); } sb.Append(fullPageName + "|1|" + (rate * 100)); } stream = new MemoryStream(Encoding.UTF8.GetBytes(sb.ToString())); filesStorageProvider.StoreFile(defaultDirectoryName + ratingFileName, stream, true); //statisticsPage.Provider.ModifyPage(statisticsPage, statisticsPageContent.Title, statisticsPageContent.User, DateTime.Now, statisticsPageContent.Comment, sb.ToString(), statisticsPageContent.Keywords, statisticsPageContent.Description, SaveMode.Normal); } /// /// Searches the plugin. /// /// The plugins array. /// The current plugin. /// /// The position of the plugin in the array, otherwise -1 /// private int SearchPlugin(string[] plugins, string currentPlugin) { for(int i = 0; i < plugins.Length; i++) { if(plugins[i].Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries)[0] == currentPlugin) return i; } return -1; } /// /// Finds the and remove first occurrence. /// /// The buffer. /// The index->content data. private KeyValuePair FindAndRemoveFirstOccurrence(StringBuilder buffer) { Match match = VotesRegex.Match(buffer.ToString()); if(match.Success) { buffer.Remove(match.Index, match.Length); return new KeyValuePair(match.Index, match); } return new KeyValuePair(-1, null); } /// /// Logs the warning. /// /// The message. private void LogWarning(string message) { if(_enableLogging) { _host.LogEntry(message, LogEntryType.Warning, null, this); } } /// /// Prepares the title of an item for display (always during phase 3). /// /// The input title. /// The context information. /// The prepared title (no markup allowed). public string PrepareTitle(string title, ContextInformation context) { return title; } /// /// Initializes the Storage Provider. /// /// The Host of the Component. /// The Configuration data, if any. /// If or are null. /// If is not valid or is incorrect. public void Init(IHostV30 host, string config) { _host = host; if(config != null) { string[] configEntries = config.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries); for(int i = 0; i < configEntries.Length; i++) { string[] configEntryDetails = configEntries[i].Split(new string[] { "=" }, 2, StringSplitOptions.None); switch(configEntryDetails[0].ToLowerInvariant()) { case "logoptions": if(configEntryDetails[1] == "nolog") { _enableLogging = false; } else { LogWarning(@"Unknown value in ""logOptions"" configuration string: " + configEntries[i] + "Supported values are: nolog."); } break; default: LogWarning("Unknown value in configuration string: " + configEntries[i]); break; } } } IFilesStorageProviderV30 filesStorageProvider = GetDefaultFilesStorageProvider(); if(!DirectoryExists(filesStorageProvider, defaultDirectoryName)) { filesStorageProvider.CreateDirectory("/", defaultDirectoryName.Trim('/')); } if(!FileExists(filesStorageProvider, defaultDirectoryName, cssFileName)) { filesStorageProvider.StoreFile(defaultDirectoryName + cssFileName, Assembly.GetExecutingAssembly().GetManifestResourceStream("ScrewTurn.Wiki.Plugins.RatingManagerPlugin.Resources.jquery.rating.css"), true); } if(!FileExists(filesStorageProvider, defaultDirectoryName, jsFileName)) { filesStorageProvider.StoreFile(defaultDirectoryName + jsFileName, Assembly.GetExecutingAssembly().GetManifestResourceStream("ScrewTurn.Wiki.Plugins.RatingManagerPlugin.Resources.jquery.rating.pack.js"), true); } if(!FileExists(filesStorageProvider, defaultDirectoryName, starImageFileName)) { filesStorageProvider.StoreFile(defaultDirectoryName + starImageFileName, Assembly.GetExecutingAssembly().GetManifestResourceStream("ScrewTurn.Wiki.Plugins.RatingManagerPlugin.Resources.star.gif"), true); } } private IFilesStorageProviderV30 GetDefaultFilesStorageProvider() { string defaultFilesStorageProviderName = _host.GetSettingValue(SettingName.DefaultFilesStorageProvider); return _host.GetFilesStorageProviders(true).First(p => p.GetType().FullName == defaultFilesStorageProviderName); } private bool DirectoryExists(IFilesStorageProviderV30 filesStorageProvider, string directoryName) { string[] directoryList = filesStorageProvider.ListDirectories("/"); foreach(string dir in directoryList) { if(dir == directoryName) return true; } return false; } private bool FileExists(IFilesStorageProviderV30 filesStorageProvider, string directory, string fileName) { string[] filesList = filesStorageProvider.ListFiles(directory); foreach(string file in filesList) { if(file == directory + fileName) return true; } return false; } /// /// Method invoked on shutdown. /// /// This method might not be invoked in some cases. public void Shutdown() { // Nothing to do } /// /// Gets the Information about the Provider. /// public ComponentInformation Information { get { return Info; } } /// /// Gets a brief summary of the configuration string format, in HTML. Returns null if no configuration is needed. /// public string ConfigHelpHtml { get { return "Specify logooptions=nolog for disabling warning log messages for exceptions."; } } } }