Exemple #1
0
        public static MetatagListModel GetMetatagListModel()
        {
            var metatags = new List <Metatag>();

            var m = new MetatagListModel("All", metatags);

            using (var db = new FusekiContext())
            {
                var allTags = db.Tags.Select(el => el.Name).ToHashSet();
                foreach (var tag in allTags)
                {
                    var mt = new Metatag();
                    mt.Name = tag;
                    var articleIds = db.Tags.Where(el => el.Name == tag).Select(el => el.ArticleId);
                    var articles   = db.Articles.Where(el => articleIds.Contains(el.Id) && el.Published).ToList();;
                    if (articles.Count == 0)
                    {
                        continue;
                    }
                    mt.Articles = articles;
                    mt.Count    = articles.Count;
                    mt.Created  = articles.OrderBy(el => el.Created).FirstOrDefault()?.Created ?? DateTime.MinValue;
                    mt.Updated  = articles.OrderByDescending(el => el.Updated).FirstOrDefault()?.Updated ?? DateTime.MinValue;
                    metatags.Add(mt);
                }
            }
            m.Metatags = metatags.OrderByDescending(el => el.Count).ThenBy(el => el.Name).ToList();
            return(m);
        }
        public IActionResult Search(string term)
        {
            var model = new SearchResultModel(Renderer);

            term       = term.ToLower();
            model.Term = term;

            using (var db = new FusekiContext())
            {
                var art = db.Articles
                          .Include(el => el.Tags)
                          .Where(el => el.Title.ToLower().Contains(term))
                          .OrderBy(el => el.Title);
                model.TitleMatches = art.ToList();

                var body = db.Articles
                           .Include(el => el.Tags)
                           .Where(el => el.Body.ToLower().Contains(term))
                           .OrderBy(el => el.Title);
                model.BodyMatches = body.ToList();

                //var tags = db.Tags.Where(el => el.Name.ToLower().Contains(term));
                //model.TagMatches = tags.ToList();
            }
            ViewData["Title"] = $"Search for: {term}";
            return(View("SearchResult", model));
        }
Exemple #3
0
        /// <summary>
        /// This is for tag viewing generically
        /// </summary>
        private string MakeTagTable(Tag tag, bool inAdmin)
        {
            var sb     = new StringBuilder();
            var header = "<table><thead><tr><th>Article<th>Body<th>Tags<th>Updated</thead><tbody>";

            sb.Append(header);
            using (var db = new FusekiContext())
            {
                var articleIds = db.Tags.Where(t => t.Name == tag.Name).Select(el => el.ArticleId);
                var articles   = db.Articles
                                 .Include(ee => ee.Tags)
                                 .Where(ee => ee.Published)
                                 .Where(el => articleIds.Contains(el.Id))
                                 .OrderBy(el => el.Title);

                foreach (var article in articles)
                {
                    var row = MakeArticleRowForList(article, false, inAdmin);
                    sb.Append(row);
                }
            }
            var end = "</tbody></table>";

            sb.Append(end);
            return(sb.ToString());
        }
Exemple #4
0
 public IActionResult PublishArticle(int id)
 {
     Logger.LogMessage($"PublishToggle: {id}");
     using (var db = new FusekiContext())
     {
         var article = db.Articles.First(el => el.Id == id);
         if (article == null)
         {
             return(new JsonResult(new { Message = "No article" }));
         }
         if (article.Published)
         {
             article.Published = false;
             db.SaveChanges();
         }
         else
         {
             if (article.Deleted)
             {
                 return(new JsonResult(new { Message = "Deleted alread" }));
             }
             article.Published = true;
             db.SaveChanges();
         }
         return(new JsonResult(new { Message = "Success", Status = article.Published }));
     }
 }
Exemple #5
0
        /// <summary>
        /// published articles with id<=294 will be have redirects for their titles.
        /// This doesn't cover the case an article title gets changed - those inbound links are just lost.
        /// </summary>
        private void RecreateHtaccess(PublishConfiguration pc)
        {
            var baseHtaccess = "RewriteEngine On\n" +
                               "Redirect permanent \"/home/comparison.html\" \"/home/ComparisonoflifeinPiscatawayNewJerseyKochiJapanandZhuzhouChina.html\"";

            var oldIds = new List <int>()
            {
                1, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 61, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 92, 93, 94, 95, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 165, 178, 179, 222, 223, 224, 226, 227, 229, 234, 235, 236, 237, 244, 246, 247, 249, 250, 260, 263, 265, 267, 268, 270, 272, 273, 275, 277, 279, 282, 288, 291, 292, 293
            };

            var lines = new List <string>();

            using (var db = new FusekiContext())
            {
                foreach (var article in db.Articles.Where(el => oldIds.Contains(el.Id) && el.Title != null && el.Title.Length > 0))
                {
                    var oldFilename = article.MakeOldFilename(false);
                    var newFilename = article.MakeFilename(false);
                    if (oldFilename != newFilename)   //doh
                    {
                        var str = $"Redirect permanent \"/home/{oldFilename}\" \"/home/{newFilename}\"";
                        lines.Add(str);
                    }
                }
            }

            baseHtaccess += "\n" + string.Join("\n", lines);
            var htaccessPath = pc.TempBase + "/.htaccess";

            System.IO.File.WriteAllText(htaccessPath, baseHtaccess);
        }
Exemple #6
0
 public Article FindArticleForInternalLink(string text)
 {
     using (var db = new FusekiContext())
     {
         var candidates = db.Articles.Where(el => el.Title.ToLower().StartsWith(text.ToLower()));
         var best       = candidates.OrderByDescending(el => el.Title.Length).FirstOrDefault();
         return(best);
     }
 }
        public IActionResult UpdateArticle(ArticleModel model)
        {
            if (ModelState.IsValid)
            {
                using (var db = new FusekiContext())
                {
                    var article = db.Articles
                                  .Include(aa => aa.Tags)
                                  .First(el => el.Id == model.Id);
                    //allow extended chars in title. But links and finding will strip them.
                    article.Title = model.Title;

                    var normalized = Renderer.Normalize(model.Body);
                    article.Body = normalized;

                    var now = DateTime.Now;
                    article.Updated = now;

                    if (article.Created == DateTime.MinValue)
                    {
                        article.Created = now;
                    }

                    //rectify tags.
                    var empty = new List <string>();
                    var tags  = model.Tags?.Split(",").Select(el => el.Trim()) ?? new string[0];

                    var newTagNames = tags
                                      .Select(el => el.Trim())
                                      .Where(ee => !string.IsNullOrWhiteSpace(ee))
                                      .ToHashSet();

                    var existingTags = article.Tags.Select(el => el.Name).ToHashSet();

                    var todelete = existingTags.Except(newTagNames);
                    var toadd    = newTagNames.Except(existingTags);

                    foreach (var bad in todelete)
                    {
                        var tag = db.Tags.Where(el => el.ArticleId == article.Id && el.Name == bad).First();
                        db.Remove(tag);
                    }

                    foreach (var good in toadd)
                    {
                        var tag = CreateTag(article, good);
                        db.Add(tag);
                    }
                    db.SaveChanges();
                    return(Redirect($"../{model.Title}"));
                }
            }
            else
            {
                return(View());
            }
        }
 public IActionResult RandomUnpublished()
 {
     using (var db = new FusekiContext())
     {
         var arti    = db.Articles.Where(el => el.Published == false && el.Deleted == false);
         var n       = new System.Random().Next(arti.Count());
         var article = arti.Skip(n).First();
         return(RedirectToAction("ViewArticle", "Admin", new { title = article.Title }));
     }
 }
 public IActionResult Index()
 {
     using (var db = new FusekiContext())
     {
         var pubs  = db.Publications.OrderByDescending(el => el.Id).ToList();
         var model = new PublicationListModel(pubs);
         ViewData["Title"] = $"Publications";
         return(View("PublicationList", model));
     }
 }
Exemple #10
0
        /// <summary>
        /// Weigh them by inverse popularity of related tag, not by count strictly.
        /// </summary>
        public List <RelatedArticle> GetRelatedArticles(Article article)
        {
            var tagnames = article.Tags.Select(el => el.Name);
            var counts   = new Dictionary <string, int>();

            using (var db = new FusekiContext())
            {
                foreach (var tag in tagnames)
                {
                    var count = db.Tags.Where(el => el.Name == tag).Count();
                    counts[tag] = count;
                }
                //calculate the related tags, and then the score of every other article in the system.

                var scoredArticles = new Dictionary <Article, double>();

                foreach (var otherArticle in db.Articles
                         .Include(el => el.Tags)
                         .Where(el => el.Published))
                {
                    if (otherArticle.Id == article.Id)
                    {
                        continue;
                    }
                    var uniqs = otherArticle.Tags.Select(el => el.Name).ToHashSet();
                    uniqs.IntersectWith(tagnames);
                    var score = uniqs.Select(el => 1.0 / counts[el]).Sum();
                    scoredArticles[otherArticle] = score;
                }

                var orderedRelated = scoredArticles.ToList().OrderByDescending(el => el.Value);
                var res            = new List <RelatedArticle>();
                foreach (var el in orderedRelated)
                {
                    if (el.Value == 0)
                    {
                        break;
                    }
                    if (res.Count > 10)
                    {
                        break;
                    }
                    var relatedArticle = db.Articles
                                         .Include(el => el.Tags)
                                         .FirstOrDefault(ra => ra.Id == el.Key.Id);

                    //doh, calculating these again.
                    //var relatedTags = relatedArticle.Tags.Where(el => tagnames.Contains(el.Name)).ToList();

                    res.Add(new RelatedArticle(relatedArticle, relatedArticle.Tags));
                }

                return(res);
            }
        }
Exemple #11
0
        public IActionResult SetTags(int id, string tagLine = "")
        {
            if (string.IsNullOrEmpty(tagLine))
            {
                tagLine = "";
            }
            var newTags      = Helpers.TagLine2Tags(tagLine);
            var didSomething = false;
            var result       = "";

            using (var db = new FusekiContext())
            {
                var image = db.Images
                            .Include(el => el.ImageTags)
                            .FirstOrDefault(el => el.Id == id);
                var exiTags = image.ImageTags ?? new List <ImageTag>();
                //exiTags = new List<ImageTag>();
                var toDelete = new List <ImageTag>();
                foreach (var tag in newTags)
                {
                    if (exiTags.FirstOrDefault(el => el.Name == tag) == null)
                    {
                        var newImageTag = new ImageTag();
                        newImageTag.Image = image;
                        newImageTag.Name  = tag;
                        db.Add(newImageTag);
                        didSomething = true;
                        result      += $"\ncreated new tag for image: {tag}";
                    }
                }

                foreach (var exiTag in exiTags)
                {
                    if (newTags.FirstOrDefault(el => el == exiTag.Name) == null)
                    {
                        db.Remove(exiTag);
                        didSomething = true;
                        result      += $"\nremoved old tag on image: {exiTag.Name}";
                    }
                }
                if (didSomething)
                {
                    db.SaveChanges();
                }
            }

            var arm = new ActionResultModel();

            arm.NextLink            = "/image/viewall";
            arm.NextLinkDescription = "back to image list";
            arm.SetResult(result);

            return(View("ActionResult", arm));
        }
Exemple #12
0
 public IActionResult ListAll()
 {
     using (var db = new FusekiContext())
     {
         var articles = db.Articles
                        .Where(el => el.Title != null && el.Title.Length > 0)
                        .Include(ee => ee.Tags)
                        .ToList();
         var m = new ListModel("All", articles);
         ViewData["Title"] = $"All articles";
         return(View("List", m));
     }
 }
Exemple #13
0
        public IActionResult CreateArticle()
        {
            using (var db = new FusekiContext())
            {
                var article = new Article();
                var rnd     = new System.Random();
                article.Title = $"draft{rnd.Next(1000)}";
                article.Body  = "";
                var a = db.Add(article);

                db.SaveChanges();
                return(Redirect($"article/edit/{a.Entity.Title}"));
            }
        }
Exemple #14
0
        private bool PublishArticlesAndTags(PublishConfiguration pc, out int count)
        {
            count = 0;
            using (var db = new FusekiContext())
            {
                var articleIds = new List <int>();
                try
                {
                    foreach (var article in db.Articles
                             .Include(el => el.Tags)
                             .Where(el => el.Published == true))
                    {
                        var filename = article.MakeFilename(false);
                        Console.WriteLine($"Writing: {filename}");
                        var path = MakePath(pc, filename);
                        //todo add in better title generation code here.

                        var combined = Renderer.GenerateArticleString(Settings, article, false);
                        System.IO.File.WriteAllText(path, combined);
                        articleIds.Add(article.Id);
                        Logger.LogMessage($"Published: {article.Title}");
                        count++;
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }


                //todo only publish tags where the article is published.
                var tags = db.Tags.Where(t => articleIds.Contains(t.ArticleId)).ToHashSet();

                var tagDir = pc.TempBase + "/tags";
                if (!System.IO.Directory.Exists(tagDir))
                {
                    System.IO.Directory.CreateDirectory(tagDir);
                }

                foreach (var tag in tags)
                {
                    PublishTag(pc, tag, false);
                }

                RecreateHtaccess(pc);
            }

            return(true);
        }
Exemple #15
0
 public IActionResult Delete(int id)
 {
     using (var db = new FusekiContext())
     {
         var image = db.Images
                     .Include(el => el.ImageTags)
                     .FirstOrDefault(el => el.Id == id);
         if (image != null)
         {
             image.Deleted = true;
         }
         db.SaveChanges();
     }
     return(RedirectToAction("ViewImages"));
 }
Exemple #16
0
 /// <summary>
 /// This works reasonably well, but doesn't penalize connections for having lots of tags NOT in common.
 /// It's also annoying that 2 is a constant, and that having increased similarity in tags doesn't help much.  i.e. 1=>2 goes in value from 1 to 1/2 to 1/3, not much when 1's are floating around
 /// </summary>
 /// <param name="a"></param>
 /// <param name="b"></param>
 /// <returns></returns>
 public static double GetTagCommonality(Article a, Article b)
 {
     using (var db = new FusekiContext())
     {
         var atags    = a.Tags.Select(el => el.Name);
         var btags    = b.Tags.Select(el => el.Name);
         var c        = atags.Intersect(btags);
         var incommon = c.Count();
         if (incommon == 0)
         {
             return(2);
         }
         return(1 / incommon);
     }
 }
Exemple #17
0
        private static string MakeTagLink(Tag tag, bool highlightTag, bool inTagDir, bool inAdmin)
        {
            var taglink   = $"{tag.MakeFilename(inAdmin)}";
            var tagFolder = inTagDir ? "" : "tags/";
            var klass     = highlightTag ? "highlight " : "";
            var tagCount  = 0;

            using (var db = new FusekiContext())
            {
                //tagCount = db.Tags.Where(el => el.Name == tag.Name && el.Article.Published == true).Count();
            }

            var line = $"<div class=\"{klass}tag\"><a class=taglink href=\"{tagFolder}{taglink}\">{tag.Name}</a></div>";

            return(line);
        }
        public IActionResult Partition(int partitionCount)
        {
            //var partitioner = new Partitioner<Article>((a, b) => Comparators.GetLengthDistance(a, b), (a, b) => Comparators.ArticleKeyLookup(a, b));
            var partitioner = new Partitioner <Article>((a, b) => Comparators.GetTagCommonality(a, b), (a, b) => Comparators.ArticleKeyLookup(a, b));

            using (var db = new FusekiContext())
            {
                var articles = db.Articles.Where(el => el.Published == true)
                               .Include(el => el.Tags).ToList();
                var r = new Random();
                articles = articles.OrderBy(el => r.NextDouble()).ToList();
                var partitiondata = partitioner.GetPartitions(partitionCount, articles);
                var model         = new ArticlePartitionModel(partitiondata);
                return(View("ArticlePartitions", model));
            }
        }
Exemple #19
0
        /// <summary>
        /// TODO: what's the difference?
        /// </summary>
        public List <RelatedArticle> GetRelatedArticlesNaive(Article article)
        {
            var tagnames = article.Tags.Select(el => el.Name);

            using (var db = new FusekiContext())
            {
                var relatedTags = db.Tags.Include(el => el.Article).Where(el => tagnames.Contains(el.Name));
                var scores      = new Dictionary <int, List <Tag> >();
                foreach (var tag in relatedTags)
                {
                    if (tag.ArticleId == article.Id)
                    {
                        continue;
                    }
                    if (!tag.Article.Published)
                    {
                        continue;
                    }
                    if (!scores.ContainsKey(tag.ArticleId))
                    {
                        scores[tag.ArticleId] = new List <Tag>();
                    }
                    scores[tag.ArticleId].Add(tag);
                }

                var orderedRelated = scores.ToList().OrderByDescending(el => el.Value.Count);
                var res            = new List <RelatedArticle>();
                foreach (var el in orderedRelated)
                {
                    if (el.Value.Count == 0)
                    {
                        break;
                    }
                    if (res.Count > 10)
                    {
                        break;
                    }
                    //var relatedArticle = db.Articles.Find(el.Key);

                    var relatedArticle = db.Articles.FirstOrDefault(ra => ra.Id == el.Key);

                    res.Add(new RelatedArticle(relatedArticle, el.Value));
                }

                return(res);
            }
        }
Exemple #20
0
        public IActionResult EditArticle(string title)
        {
            using (var db = new FusekiContext())
            {
                var article = db.Articles
                              .Include(el => el.Tags)
                              .First(el => el.Title.StartsWith(title));
                //startswith to allow titles with ? marks in them. Doh.

                var normalized = Renderer.Normalize(article.Body);
                article.Body = normalized;
                var liveUrl = string.Format(Settings.LiveUrlTemplate, article.MakeFilename(false), true);
                var editUrl = string.Format(Settings.EditUrlTemplate, article.Title, false);
                var model   = new ArticleModel(article, liveUrl, editUrl, Renderer.ToHtml(normalized));
                ViewData["Title"] = $"Editing {article.Title}";
                return(View("EditArticle", model));
            }
        }
Exemple #21
0
        public IActionResult ViewImageTag(string term)
        {
            using (var db = new FusekiContext())
            {
                var model = new ViewImagesModel();
                model.Term = term;
                term       = term.ToLower();
                var    images    = new List <Image>();
                string matchType = "";
                var    tag       = db.ImageTags.FirstOrDefault(el => el.Name.ToLower() == term);
                if (tag == null)
                {
                    tag       = db.ImageTags.FirstOrDefault(el => el.Name.ToLower().StartsWith(term));
                    matchType = "prefix";
                }
                else if (tag == null)
                {
                    tag       = db.ImageTags.FirstOrDefault(el => el.Name.ToLower().Contains(term));
                    matchType = "substring";
                }
                else if (tag == null)
                {
                    tag       = null;
                    matchType = "none";
                }
                else
                {
                    matchType = "exact";
                }

                if (tag != null)
                {
                    var tagName = tag.Name;
                    var tags    = db.ImageTags.Where(el => el.Name == tagName);
                    images = tags.Select(el => el.Image)
                             .Include(el => el.ImageTags)
                             .ToList();
                }

                model.Images    = images;
                model.MatchType = matchType;
                return(View("ViewImages", model));
            }
        }
        public IActionResult Publish()
        {
            var model = new PublicationResultModel();

            var publishResult = Publisher.Publish();

            var publication = new Publication();

            publication.ArticleCount    = publishResult.Count;
            publication.PublicationTime = DateTime.Now;
            using (var db = new FusekiContext())
            {
                db.Add(publication);
                db.SaveChanges();
            }
            model.Publication = publication;
            ViewData["Title"] = $"PublicationResult";
            return(View("PublicationResult", model));
        }
Exemple #23
0
        public IActionResult RestoreImages()
        {
            var images = System.IO.Directory.GetFiles(PublishConfiguration.ImageSource).Select(el => el.Replace(PublishConfiguration.ImageSource, "").Replace("\\", ""));

            using (var db = new FusekiContext())
            {
                foreach (var imagefn in images)
                {
                    var exi = db.Images.FirstOrDefault(el => el.Filename == imagefn);
                    if (exi == null)
                    {
                        var image = new Image();
                        image.Filename = imagefn;
                        db.Add(image);
                    }
                }
                db.SaveChanges();
            }

            return(null);
        }
Exemple #24
0
        public IActionResult Search(string term)
        {
            Logger.LogMessage($"Searched for: {term}");
            var model = new SearchResultModel(Renderer);

            term       = term.ToLower();
            model.Term = term;

            using (var db = new FusekiContext())
            {
                var art = db.Articles.Where(el => el.Title.ToLower().Contains(term));
                model.TitleMatches = art.ToList();

                var body = db.Articles.Where(el => el.Body.ToLower().Contains(term));
                model.BodyMatches = body.ToList();

                //var tags = db.Tags.Where(el => el.Name.ToLower().Contains(term));
                //model.TagMatches = tags.ToList();
            }

            return(new JsonResult(model));
        }
Exemple #25
0
 public IActionResult Tag(string name)
 {
     using (var db = new FusekiContext())
     {
         var tag = db.Tags
                   .Where(el => el.Name == name).FirstOrDefault();
         if (tag == null)
         {
             return(Redirect("../../"));
         }
         var articleIds = db.Tags.Where(el => el.Name == name).Select(el => el.ArticleId);
         var articles   = db.Articles
                          .Where(el => articleIds.Contains(el.Id))
                          .Where(el => el.Published)
                          .Include(el => el.Tags)
                          .OrderBy(el => el.Title)
                          .ToList();
         var model = new ListModel($"Tag: {tag.Name}", articles, name);
         ViewData["Title"] = $"Search: {name}";
         return(View("List", model));
     }
 }
Exemple #26
0
        public IActionResult ViewImages(string term)
        {
            using (var db = new FusekiContext())
            {
                var model = new ViewImagesModel();
                model.Term = term;
                IOrderedQueryable <Image> images;
                if (!string.IsNullOrEmpty(term))
                {
                    images     = db.Images.Where(el => el.Filename.ToLower().Contains(term.ToLower())).OrderByDescending(el => el.Id);
                    model.Term = "Search for: " + term;
                }
                else
                {
                    images = db.Images.OrderByDescending(el => el.Id).Take(20).OrderByDescending(el => el.Id);
                }

                model.Images = images
                               .Where(el => el.Deleted == false)
                               .Include(el => el.ImageTags)
                               .ToList();
                return(View("ViewImages", model));
            }
        }
Exemple #27
0
        public IActionResult ViewArticle(string title)
        {
            using (var db = new FusekiContext())
            {
                var article = db.Articles
                              .Include(ee => ee.Tags)
                              .FirstOrDefault(el => el.Title.StartsWith(title));
                //startswith to fix question mark thing.

                if (article == null)
                {
                    return(RedirectToAction("List"));;
                }

                var related = ArticleData.GetRelatedArticles(article);

                var liveUrl       = string.Format(Settings.LiveUrlTemplate, article.MakeFilename(true));
                var editUrl       = string.Format(Settings.EditUrlTemplate, article.Title, false);
                var articleString = Renderer.GenerateArticleString(Settings, article, true);
                var model         = new ArticleModel(article, liveUrl, editUrl, articleString, related);
                ViewData["Title"] = $"{article.Title}";
                return(View("Article", model));
            }
        }
        public IActionResult Partition2(int partitionCount)
        {
            using (var db = new FusekiContext())
            {
                var articles = db.Articles.Where(el => el.Published == true)
                               .Include(el => el.Tags).Take(20).ToList();
                //get a tag vector for each article.

                var allTags = new HashSet <string>();

                //TODO: What happens if we remove all tags which only occur once.
                foreach (var article in articles)
                {
                    foreach (var tag in article.Tags)
                    {
                        allTags.Add(tag.Name);
                    }
                }

                var newAllTags = new HashSet <string>();
                foreach (var t in allTags)
                {
                    var relatedArticles = db.Articles.Where(el => el.Tags.Select(tag => tag.Name).Contains(t));
                    if (relatedArticles.Count() > 1)
                    {
                        newAllTags.Add(t);
                    }
                }

                allTags = newAllTags;

                var allTagsOrdered = allTags.OrderBy(el => el);

                var obs  = new List <List <double> >();
                var dict = new Dictionary <string, object>();

                foreach (var article in articles)
                {
                    var articleTags = article.Tags.Select(el => el.Name);
                    var vector      = new List <double>();
                    foreach (var tag in allTagsOrdered)
                    {
                        if (articleTags.Contains(tag))
                        {
                            vector.Add(1);
                        }
                        else
                        {
                            vector.Add(0);
                        }
                    }
                    obs.Add(vector);
                }

                var vecvec = obs.Select(el => el.ToArray()).ToArray();

                var kmeans = new KMeans(k: partitionCount);

                var clusters = kmeans.Learn(vecvec);
                dict["Kmeans Error"]   = kmeans.Error;
                dict["dimensionality"] = kmeans.Dimension;
                dict["Iterations"]     = kmeans.Iterations;
                dict["MaxIterations"]  = kmeans.MaxIterations;
                dict["Tolerance"]      = kmeans.Tolerance;


                int[] labels = clusters.Decide(vecvec);
                //labels is array[articleId] => partitionNumber
                var ii    = 0;
                var psets = new List <PartitionSet <Article> >();

                //this is totally fake. TODO: refactor these to be dumber - no need to have comparators etc.
                var dm = new DistanceMetrics <Article>((a, b) => Comparators.GetTagCommonality(a, b), (a, b) => Comparators.ArticleKeyLookup(a, b));
                while (ii < partitionCount)
                {
                    //TODO: is accord zero indexed?
                    psets.Add(new PartitionSet <Article>(dm, ii));
                    ii++;
                }
                var index = 0;
                foreach (var l in labels)
                {
                    var article = articles[index];
                    index++;
                    psets[l].Add(article);
                }


                var partitiondata = new PartitionData <Article>(psets, dict);

                var model = new ArticlePartitionModel(partitiondata);
                return(View("ArticlePartitions", model));
            }
        }
Exemple #29
0
        ///obviously impossible to test every possibility.
        ///Might be possible to iterate or do local hill climbing?  order matters for all that.
        ///title length has weird transitivity; don't use that because it won't apply for other metrics.
        ///I could just do it 100 times with random starts, iterating adding members to the set which they are closest to.
        ///Then as a final step test each element to see if it belongs better in another set.

        public PartitionData <T> GetPartitions(int partitionCount, List <T> Elements)
        {
            if (partitionCount < 2 || partitionCount > 100)
            {
                throw new Exception("Are you sure you want to generate that many partitions?");
            }

            var sets = new List <PartitionSet <T> >();
            var ii   = 0;

            while (ii < partitionCount)
            {
                var px = new PartitionSet <T>(metrics, ii);
                sets.Add(px);
                ii++;
            }

            using (var db = new FusekiContext())
            {
                foreach (var el in Elements)
                {
                    var targetSet = FindBestPartition(el, sets);
                    targetSet.Add(el);
                }
            }

            //initial assignment done.
            //now iterate over each item, removing it and then readding it where it belongs til we reach stability or N iterations.
            var loopCt = 0;
            var moveCt = 100;

            var stats = new Dictionary <string, object>();

            stats["InitialQuality"] = FindQuality(sets);

            while (loopCt < 200)
            {
                moveCt = 0;
                var PlannedMoves = new Dictionary <T, Tuple <PartitionSet <T>, PartitionSet <T> > >();
                foreach (var set in sets)
                {
                    foreach (var el in set.Items)
                    {
                        //remove it first so it has a free choice
                        var targetSet = FindBestPartition(el, sets);
                        if (targetSet != set)
                        {
                            moveCt++;
                            var data = new Tuple <PartitionSet <T>, PartitionSet <T> >(set, targetSet);
                            PlannedMoves[el] = data;
                        }
                        if (moveCt > 0)
                        {
                            break;
                        }
                    }
                    if (moveCt > 0)
                    {
                        break;
                    }
                }

                //problem: I am moving to favor the article, not to favor the overall quality of matches.  i.e. if there is a linking article who is happier in a dedicated node, but removing him hurts the parent, how to do it?
                foreach (var article in PlannedMoves.Keys)
                {
                    var tup    = PlannedMoves[article];
                    var old    = tup.Item1;
                    var newset = tup.Item2;
                    old.Remove(article);
                    newset.Add(article);
                }
                loopCt++;
                stats[$"quality:{loopCt} moved:{moveCt}"] = FindQuality(sets);
                if (moveCt == 0)
                {
                    break;
                }
            }

            stats["moveCt"]        = moveCt;
            stats["loopCt"]        = loopCt;
            stats["Final quality"] = FindQuality(sets);

            var pdata = new PartitionData <T>(sets, stats);

            return(pdata);
        }
Exemple #30
0
        public IActionResult UploadPost(UploadFileModel file, string tagLine)
        {
            //possibly accept the override filename

            var filename = file.Image.FileName;

            if (string.IsNullOrEmpty(file.Filename))
            {
                file.Filename = file.Filename.ToLower();
            }
            else
            {
                filename = file.Filename;
            }

            filename = CleanFilename(filename);

            if (!ValidateImageExtension(filename))
            {
                var extFromImage = Path.GetExtension(file.Image.FileName);

                if (ValidateImageExtension(extFromImage))
                {
                    filename = filename + extFromImage;
                }
                else
                {
                    throw new Exception("Invalid extension on filename" + filename);
                }
            }

            var targetPath = $"{PublishConfiguration.ImageSource}/{filename}";

            if (System.IO.File.Exists(targetPath))
            {
                throw new System.Exception("Already exists.");
            }

            using (var stream = System.IO.File.Create(targetPath))
            {
                file.Image.CopyTo(stream);
            }

            using (var db = new FusekiContext())
            {
                var image = new Image();
                image.Filename = filename;
                db.Add(image);
                var tags = Helpers.TagLine2Tags(tagLine);
                foreach (var tag in tags)
                {
                    var t = new ImageTag();
                    t.Image = image;
                    t.Name  = tag;
                    db.Add(t);
                }
                db.SaveChanges();
            }

            var arm = new ActionResultModel();

            arm.NextLink            = "/image/upload";
            arm.NextLinkDescription = "Return to image upload";
            arm.SetResult("Uploaded image");
            return(View("ActionResult", arm));
        }