public static AtomEntry MakeTestEntry(DateTime published, string collectionName)
        {
            string owner = string.Format("{0}.someblog.com", TestWorkspaceName);
            string path = "path" + RandomChars(12);
            Id entryId = new Id(owner, published, collectionName, path);

            return new AtomEntry
            {
                Title = new AtomText
                {
                    Text = "Test entry " + Guid.NewGuid(),
                    Type = "text"
                },
                Content = new AtomContent
                {
                    Text = "Test entry " + Guid.NewGuid(),
                    Type = "text"
                },
                Summary = new AtomText
                {
                    Text = "This entry is generated test data",
                    Type = "text"
                },
                Control = new AppControl
                {
                    AllowAnnotate = true,
                    Approved = true,
                    Draft = false
                },
                Id = entryId,
                Published = published
            };
        }
    public RaterModel Rate(Id entryId, float rating, User user, string ip)
    {
      LogService.Info("Rater.Rate entryId={0} rating={1} ip={2}", entryId, rating, ip);

      if (!AuthorizeService.IsAuthorized(user, entryId.ToScope(), AuthAction.RateEntryOrMedia))
        throw new UserNotAuthorizedException(user.Name, AuthAction.RateEntryOrMedia.ToString());

      if (rating < 1 || rating > 5) throw new ArgumentOutOfRangeException("Rating value must be 1 thru 5.");

      AtomEntry entry = AtomEntryRepository.GetEntry(entryId);
      if (entry.Raters.Contains(ip)) throw new UserAlreadyRatedEntryException(ip, entry.Id.ToString());

      entry.RatingCount++;
      entry.RatingSum += (int)Math.Round(rating);
      entry.Edited = DateTimeOffset.UtcNow;
      List<string> raters = entry.Raters.ToList();
      raters.Add(ip);
      entry.Raters = raters;
      entry = AtomEntryRepository.UpdateEntry(entry);
      return new RaterModel()
      {
        PostHref = RouteService.RouteUrl("RaterRateEntry", entryId),
        Rating = entry.Rating,
        CanRate = false,
        RatingCount = entry.RatingCount
      };
    }
 public string GetCategoriesPath(Id collectionId, AppCategories externalCats)
 {
   string filename = externalCats.GetProperty<string>(FileNs + "name");
   if (string.IsNullOrEmpty(filename)) filename = DefaultCategoriesFileName;
   string path = GetCollectionPath(collectionId);
   path = Path.Combine(path, filename);
   return path;
 }
 public AppCategories GetCategories(Id collectionId, AppCategories externalCats)
 {
   string path = pathResolver.GetCategoriesPath(collectionId, externalCats);
   try
   {
     return AppCategories.Load(path);//TODO: cache
   }
   catch (FileNotFoundException)
   {
     throw new ResourceNotFoundException("categories document", path);
   }
 }
 public RaterModel GetRaterModel(Id entryId, User user, string ip)
 {
   bool auth = AuthorizeService.IsAuthorized(user, entryId.ToScope(), AuthAction.RateEntryOrMedia);
   AtomEntry entry = AtomEntryRepository.GetEntry(entryId);
   return new RaterModel()
   {
     PostHref = RouteService.RouteUrl("RaterRateEntry", entryId),
     Rating = entry.Rating,
     CanRate = auth && !entry.Raters.Contains(ip),
     RatingCount = entry.RatingCount
   };
 }
        private static int IndexOfId(this IList<AppCollection> list, Id id) 
        {
            string idString = id.ToString();
            for (int index = 0; index < list.Count; index++)
            {
                if (String.Equals(idString, list[index].Id.ToString())) 
                {
                    return index;
                }
            }

            return -1;
        }
    public BlogMLBlog Export(Id entryCollectionId, Id pagesCollectionId, Id mediaCollectionId)
    {
      LogService.Info("Beginning export of collection with Id='{0}'", entryCollectionId);
      BlogMLBlog blog = new BlogMLBlog();
      AppService appSvc = AtomPubService.GetService();

      AppCollection coll = appSvc.GetCollection(entryCollectionId);

      blog.Title = coll.Title.Text;
      if (coll.Subtitle != null) blog.SubTitle = coll.Subtitle.Text;
      blog.RootUrl = coll.Href.ToString();

      //extended properties
      blog.ExtendedProperties.Add(new BlogML.Pair<string, string>("CommentModeration", AuthorizeService.IsAuthorized(AuthRoles.Anonymous, coll.Id.ToScope(),
        AuthAction.ApproveAnnotation) ? "Anonymous" : "Authenticated"));
      blog.ExtendedProperties.Add(new BlogML.Pair<string, string>("SendTrackback", new BlogAppCollection(coll).TrackbacksOn ? "Yes" : "No"));

      foreach (BlogMLCategory cat in coll.AllCategories.Select(c => new BlogMLCategory()
      {
        ID = c.Term,
        Approved = true,
        DateCreated = DateTime.UtcNow,
        DateModified = DateTime.UtcNow,
        Title = c.ToString()
      })) { blog.Categories.Add(cat); }

      IPagedList<AtomEntry> entries = null;
      int page = 0;
      do
      {
        entries = AtomPubService.GetEntries(new EntryCriteria() { WorkspaceName = entryCollectionId.Workspace, CollectionName = entryCollectionId.Collection, Authorized = true },
        page, 100); page++;
        foreach (AtomEntry entry in entries)
        {
          try
          {
            LogService.Info("Processing entry with ID='{0}'", entry.Id);
            AddEntry(entry, blog);
          }
          catch (Exception ex)
          {
            LogService.Error(ex);
          }
        }
      } while (entries.PageIndex < entries.PageCount);

      LogService.Info("Finished export!");
      return blog;
    }
        public static Id MakeReplyId(Id parent, DateTime published)
        {
            if (!Uri.IsWellFormedUriString(parent.ToString(), UriKind.RelativeOrAbsolute))
            {
                throw new Exception("id is not a valid uri: " + parent);
            }

            string childPath = RandomChars(12);
            Id resultId = new Id(parent.Owner, published, parent.Collection, parent.EntryPath + "," + childPath);

            string uriString = resultId.ToString();
            if (!Uri.IsWellFormedUriString(resultId.ToString(), UriKind.RelativeOrAbsolute))
            {
                throw new Exception("id is not a valid uri: " + uriString);
            }

            return resultId;
        }
    public AtomEntry CreateMedia(AtomEntry entry, Stream stream)
    {
      //TODO: transaction

      string path = pathResolver.GetMediaLinkEntryPath(entry.Id);
      Id id = entry.Id;
      int i = 1;
      while (System.IO.File.Exists(path))
      {
        id = new Id(id.Owner, id.Date, id.Collection, entry.Id.EntryPath + i++);
        path = pathResolver.GetEntryPath(id);
      }
      entry.Id = id;

      path = pathResolver.GetMediaPath(entry.Id, entry.Content.Type);
      FileHelper.WriteStream(stream, path);

      //create & return the media link entry
      return atomEntryRepository.CreateEntry(entry);
    }
    public AtomEntry GetEntry(Id entryId)
    {
      ItemDataContext dc = new ItemDataContext();
      Item item = dc.Items.Where(i => i.Id == entryId.ToString()).SingleOrDefault();
      SyndicationItem si = new SyndicationItem()
      {
        Id = item.Id,
        LastUpdatedTime = item.LastUpdatedTime,
        PublishDate = item.PublishDate.Value
      };
      if (!string.IsNullOrEmpty(item.BaseUri)) si.BaseUri = new Uri(item.BaseUri);

      LoadAttributes(si.AttributeExtensions, item.Attributes);
      LoadElements(si.ElementExtensions, item.Elements);
      LoadPersons(si.Authors, item.Persons, PersonTypeAuthor);
      LoadPersons(si.Contributors, item.Persons, PersonTypeContributor);
      si.Content = GetContent(item.Content);
      si.Title = GetTextContent(item.Title);
      si.Summary = GetTextContent(item.Summary);
      si.Copyright = GetTextContent(item.Copyright);
      LoadLinks(si.Links, item.Links);
      LoadCategories(si.Categories, item.Categories);

      using (Stream s = new MemoryStream())
      {
        XmlWriter w = new XmlTextWriter(s, Encoding.UTF8);
        si.GetAtom10Formatter().WriteTo(w);
        w.Flush();
        AtomEntry entry = new AtomEntry();
        s.Position = 0;
        XmlReader r = new XmlTextReader(s);
        entry.Xml = XElement.Load(r);
        //entry.ReadXml(r);
        return entry;
      }
    }
 public AtomEntry GetEntry(Id entryId)
 {
     return GetEntryById(entryId);
 }
    public virtual Uri RouteUrl(string routeName, Id id, RouteValueDictionary routeData, AbsoluteMode abMode)
    {
      if (routeData == null) routeData = new RouteValueDictionary();
      if (id != null)
      {
        if (AppService.ServiceType == ServiceType.MultiFolder)
        {
          routeData["workspace"] = id.Workspace;
        }

        routeData["collection"] = id.Collection;

        //dated resource
        if (id.Date.Length == 10 && AppService.GetCollection(id).Dated)
        {
          routeData["year"] = id.Date.Substring(0, 4);
          routeData["month"] = id.Date.Substring(5, 2);
          routeData["day"] = id.Date.Substring(8, 2);
          if (!routeName.EndsWith("Dated")) routeName = routeName + "Dated";
        }

        if (!string.IsNullOrEmpty(id.EntryPath))
          routeData["path"] = id.EntryPath;
      }

      VirtualPathData path = Routes.GetVirtualPath(Context, routeName, routeData);
      string url = path == null ? string.Empty : path.VirtualPath;
      return ToUri(routeName, url, abMode);
    }
    public virtual AtomFeed GetAnnotations(Id id, bool deep, int pageIndex, int pageSize)
    {
      LogService.Info("AnnotateService.GetAnnotations: {0} deep={1}", id, deep);

      //authorization
      if (!AuthorizeService.IsAuthorized(GetUser(), id.ToScope(), AuthAction.GetAnnotations))
        throw new UserNotAuthorizedException(GetUser().Name, AuthAction.GetAnnotations.ToString());

      return GetAnnotations(new EntryCriteria()
      {
        EntryId = id.EntryPath != null ? id : null,
        WorkspaceName = id.EntryPath == null ? id.Workspace : null,
        CollectionName = id.EntryPath == null ? id.Collection : null,
        SortMethod = id.EntryPath == null ? SortMethod.DateDesc : SortMethod.Default,
        Authorized = AuthorizeService.IsAuthorized(GetUser(), id.ToScope(), AuthAction.GetEntryOrMedia),
        Annotations = true,
        Deep = deep
      }, pageIndex, pageSize);
    }
    public virtual AtomEntry Annotate(Id entryId, AtomEntry entry, string slug)
    {
      LogService.Info("AnnotateService.Annotate entryId={0} slug={1}", entryId, slug);

      //authorization
      if (!AuthorizeService.IsAuthorized(GetUser(), entryId.ToScope(), AuthAction.Annotate))
        throw new UserNotAuthorizedException(GetUser().Name, AuthAction.Annotate.ToString());

      AppCollection coll = AppService.GetCollection(entryId);

      //make sure type is accepted
      if (!coll.CanAccept(Atom.ContentTypeEntry))
        throw new InvalidContentTypeException(Atom.ContentTypeEntry);

      entry.SetNamespaces(); //TODO: is there a better place for this?

      //build id onto parent's id
      AtomEntry parent = AtomPubService.GetEntry(entryId);
      entry.Id = new Id(parent.Id.Owner, parent.Id.Date, parent.Id.Collection, entry.BuildPath(parent.Id.EntryPath, slug));
      
      var url = new UrlHelper(Container.GetInstance<RequestContext>());
      //this annotation is a reply to the parent entry, TODO: leave off href for later calc based on id?
      entry.InReplyTo = new ThreadInReplyTo()
      {
        Ref = parent.Id,
        Href = parent.IsExternal ? parent.Content.Src : url.RouteIdUri("AtomPubEntry", entry.Id, AbsoluteMode.Force),
        Type = parent.IsExternal ? parent.Content.Type : Atom.ContentTypeEntry
      };

      if (!entry.Published.HasValue) entry.Published = DateTimeOffset.UtcNow;
      entry.Updated = DateTimeOffset.UtcNow;
      entry.Edited = DateTimeOffset.UtcNow;

      if (entry.Authors.Count() == 0) entry.SetPerson(AuthorizeService, true);

      //entry.IdChanged += (e) => e.UpdateLinks(UrlHelper.RouteIdUri);

      //OnAnnotate(parent, entryId, entry, slug);
      if (AnnotatingEntry != null) AnnotatingEntry(entryId, entry, slug);

      if (entry.Authors.Count() == 0 || entry.Authors.First().Name == null)
        throw new AnnotationNotAllowedException(entry.Id, entry.AnnotationType, "the author cannot be determined");

      entry = AtomEntryRepository.CreateEntry(entry);
      if (EntryAnnotated != null) EntryAnnotated(entry);
      return entry;
    }
        private List<Domain.AtomEntry> GetAnnotations(Id parentEntryId, bool deep)
        {
            Domain.AtomEntry parent = GetEntryById(parentEntryId);

            if (parent != null)
            {
                return GetAnnotations(parent, deep);
            }
            else
            {
                return new List<Domain.AtomEntry>();
            }
        }
        public int ApproveAll(Id id)
        {
            List<AtomEntry> entriesToUpdate = new List<AtomEntry>();
            AtomEntry rootEntry = GetEntryById(id);

            if (! rootEntry.Approved)
            {
                entriesToUpdate.Add(rootEntry);
            }

            entriesToUpdate.AddRange(GetAnnotations(rootEntry, true));

            // update all of the entries that are not yet approved
            int authCount = 0;
            DateTimeOffset dateApproval = DateTimeOffset.Now;

            foreach (AtomEntry entry in entriesToUpdate)
            {
                if (!entry.Approved)
                {
                    authCount++;
                    entry.Control.Approved = true;
                    entry.Edited = dateApproval;
                }
            }

            return authCount;
        }
        private int IndexOfId(Id id)
        {
            string idString = id.ToString();

            for (int loopIndex = 0; loopIndex < entriesList.Count(); loopIndex++)
            {
                if (entriesList[loopIndex].Id.ToString() == idString)
                {
                    return loopIndex;
                }
            }

            return -1;
        }
 public string GetEntryEtag(Id entryId)
 {
     string key = entryId.ToString();
     if (eTags.ContainsKey(key))
     {
         // return the entry Id with a version apended
         return key + "::" + eTags[key];
     }
     else
     {
         return string.Empty;
     }
 }
 /// <summary>
 /// Delete an entry by id
 /// </summary>
 /// <param name="entryId"></param>
 public void DeleteEntry(Id entryId)
 {
     int index = IndexOfId(entryId);
     if (index >= 0)
     {
         entriesList.RemoveAt(index);
     }
 }
 public AtomCategory AddCategory(Id collectionId, string category, Uri scheme)
 {
   LogService.Info("AtomPubService.AddCategory collectionId={0}, category={1}", collectionId, category);
   AppService service = AppServiceRepository.GetService();
   AppCollection coll = service.GetCollection(collectionId);
   AtomCategory cat = new AtomCategory() { Term = category, Scheme = scheme };
   //TODO: support external categories
   //TODO: support scheme
   bool changed = coll.Categories.First().AddCategory(cat);
   //save when changed
   if (changed)
   {
     LogService.Info("Saving service doc for internal category change.");
     AppServiceRepository.UpdateService(service);
   }
   return cat;
 }
        public void ApproveEntry(Id entryId)
        {
            AtomEntry entry = GetEntryById(entryId);

            entry.Control.Approved = true;
            entry.Updated = DateTime.Now;
        }
 public void RemoveCategory(Id collectionId, string category, Uri scheme)
 {
   LogService.Info("AtomPubService.RemoveCategory collectionId={0}, category={1}", collectionId, category);
   bool changed = false;
   AppService service = AppServiceRepository.GetService();
   AppCollection coll = service.GetCollection(collectionId);
   AppCategories cats = coll.Categories.Where(c => c.Scheme == scheme).FirstOrDefault();
   if (cats != null)
   {
     var list = cats.Categories.ToList();
     var cat = list.Where(c => c.Term == category).SingleOrDefault();
     if (cat != null)
     {
       list.Remove(cat);
       cats.Categories = list;
       changed = true;
     }
   }
   //save when changed
   if (changed)
   {
     LogService.Info("Saving service doc for internal category change.");
     AppServiceRepository.UpdateService(service);
   }
 }
        private IQueryable<AtomEntry> FilterResultsByAnnotations(IQueryable<AtomEntry> results, Id parentEntryId, bool deep)
        {
            List<AtomEntry> annotations = GetAnnotations(parentEntryId, deep);
            List<string> annotationIds = new List<string>(from an in annotations select an.Id.ToString());

            return results.Where(ent => annotationIds.Contains(ent.Id.ToString()));
        }
 public virtual Uri RouteUrl(string routeName, Id id)
 {
   return RouteUrl(routeName, id, AbsoluteMode.Default);
 }
 private AtomEntry GetEntryById(Id entryId)
 {
     return entriesList.Where(entry => entry.Id.ToString() == entryId.ToString()).SingleOrDefault();
 }
 public virtual Uri RouteUrl(string routeName, Id id, AbsoluteMode abMode)
 {
   return RouteUrl(routeName, id, null, abMode);
 }
 public virtual AtomEntry MediaAnnotate(Id entryId, Stream stream, string slug, string contentType)
 {
   LogService.Info("AnnotateService.MediaAnnotate entryId={0} slug={1} contentType={2}", entryId, slug, contentType);
   throw new NotImplementedException();
 }
 public virtual Uri RouteUrl(string routeName, Id id, RouteValueDictionary routeData)
 {
   return RouteUrl(routeName, id, routeData, AbsoluteMode.Default);
 }
    public virtual AnnotationState GetAnnotationState(AppCollection coll, Id entryId)
    {
      LogService.Info("AnnotateService.GetAnnotationState entryId={0}", entryId);

      if (!coll.AnnotationsOn)
      {
        return AnnotationState.Off;
      }
      else if (!AuthorizeService.IsAuthorized(GetUser(), entryId.ToScope(), AuthAction.Annotate))
      {
        return AnnotationState.Unauthorized;
      }
      else if (!AtomEntryRepository.GetEntry(entryId).AllowAnnotate)
      {
        return AnnotationState.Closed;
      }
      //TODO: handle expired
      return AnnotationState.On;
    }
 public virtual Uri RouteUrl(string routeName, Id id, object routeData, AbsoluteMode abMode)
 {
   var dic = routeData == null ? new RouteValueDictionary() :
     routeData is RouteValueDictionary ? (RouteValueDictionary)routeData :
     new RouteValueDictionary(routeData);
   return RouteUrl(routeName, id, dic, abMode);
 }