big refactoring, and more

New routes, new juice flow, the tags on posts
main
Paul Schneider 10 years ago
parent d04a68db01
commit 1805cb3e17
46 changed files with 1339 additions and 515 deletions

@ -1,3 +1,7 @@
2015-10-17 Paul Schneider <paul@pschneider.fr>
* NpgsqlBlogProvider.cs:
2015-10-13 Paul Schneider <paul@pschneider.fr>
* NpgsqlBlogProvider.cs: implements the tag methods on db

@ -33,8 +33,8 @@ namespace Npgsql.Web.Blog
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
cmd.CommandText = "INSERT INTO tagged (tagid,postid) VALUES (:tid,:pid)";
cmd.Parameters.AddWithValue("tid",tid);
cmd.Parameters.AddWithValue("pid",postid);
cmd.Parameters.AddWithValue ("tid", tid);
cmd.Parameters.AddWithValue ("pid", postid);
cnx.Open ();
cmd.ExecuteNonQuery ();
return tid;
@ -47,8 +47,9 @@ namespace Npgsql.Web.Blog
/// <param name="postid">Postid.</param>
/// <param name="tagid">Tagid.</param>
/// <param name="name">Name.</param>
override public void Untag(long postid, string name) {
Untag(postid, GetTagId (name));
override public void Untag (long postid, string name)
{
Untag (postid, GetTagId (name));
}
/// <summary>
@ -57,7 +58,8 @@ namespace Npgsql.Web.Blog
/// <param name="postid">Postid.</param>
/// <param name="tagid">Tagid.</param>
/// <param name="tid">Tid.</param>
override public void Untag(long postid, long tid) {
override public void Untag (long postid, long tid)
{
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
cmd.CommandText = "DELETE FROM tagged WHERE postid = :pid AND tagid = :tid";
@ -67,6 +69,7 @@ namespace Npgsql.Web.Blog
cmd.ExecuteNonQuery ();
}
}
/// <summary>
/// Gets the comments.
/// </summary>
@ -77,32 +80,33 @@ namespace Npgsql.Web.Blog
{
List<Comment> cmts = new List<Comment> ();
using (NpgsqlConnection cnx=new NpgsqlConnection(connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand()) {
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
cmd.CommandText = "select _id, username, bcontent, modified, posted, visible from comment " +
"where applicationname = :appname and postid = :id" +
((getHidden) ? " and visible = true ":" ") +
"order by posted asc" ;
"where applicationname = :appname and postid = :id" +
((getHidden) ? " and visible = true " : " ") +
"order by posted asc";
cmd.Parameters.AddWithValue ("appname", applicationName);
cmd.Parameters.AddWithValue ("id", postid);
cnx.Open ();
using (NpgsqlDataReader rdr = cmd.ExecuteReader()) {
using (NpgsqlDataReader rdr = cmd.ExecuteReader ()) {
while (rdr.Read ()) {
Comment c = new Comment();
Comment c = new Comment ();
c.CommentText = rdr.GetString (rdr.GetOrdinal ("bcontent"));
c.From = rdr.GetString (rdr.GetOrdinal ("username"));
c.Modified = rdr.GetDateTime (rdr.GetOrdinal ("modified"));
c.Posted = rdr.GetDateTime (rdr.GetOrdinal ("posted"));
c.Visible = rdr.GetBoolean (rdr.GetOrdinal ("visible"));
c.PostId = postid;
c.Id = rdr.GetInt64(rdr.GetOrdinal("_id"));
c.Id = rdr.GetInt64 (rdr.GetOrdinal ("_id"));
cmts.Add (c);
}
}
}
return cmts.ToArray();
return cmts.ToArray ();
}
/// <summary>
/// Updates the post.
/// </summary>
@ -112,9 +116,9 @@ namespace Npgsql.Web.Blog
/// <param name="visible">If set to <c>true</c> visible.</param>
/// <param name="cids">Circle identifiers</param>
public override void UpdatePost (long postid, string title, string content,
bool visible, long [] cids)
bool visible, long[] cids)
{
using (NpgsqlConnection cnx = new NpgsqlConnection(connectionString)) {
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString)) {
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
DateTime now = DateTime.Now;
cmd.CommandText =
@ -131,10 +135,11 @@ namespace Npgsql.Web.Blog
cnx.Open ();
cmd.ExecuteNonQuery ();
}
cnx.Close();
cnx.Close ();
}
UpdatePostCircles (postid, cids);
}
/// <summary>
/// Removes the post.
/// </summary>
@ -146,9 +151,10 @@ namespace Npgsql.Web.Blog
cmd.CommandText = "delete from blog where _id = :id";
cmd.Parameters.AddWithValue ("id", postid);
cnx.Open ();
cmd.ExecuteNonQuery();
cmd.ExecuteNonQuery ();
}
}
/// <summary>
/// Comment the specified from, postid and content.
/// </summary>
@ -158,17 +164,17 @@ namespace Npgsql.Web.Blog
public override long Comment (string from, long postid, string content)
{
if (from == null)
throw new ArgumentNullException("from");
throw new ArgumentNullException ("from");
if (content == null)
throw new ArgumentNullException("content");
throw new ArgumentNullException ("content");
bool visible = AutoValidatesComments;
using (NpgsqlConnection cnx=
new NpgsqlConnection(connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand()) {
using (NpgsqlConnection cnx =
new NpgsqlConnection (connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
cmd.CommandText = "insert into comment (postid,bcontent," +
"modified,posted,visible,username,applicationname)" +
"values (:postid,:bcontent,:modified,:posted," +
":visible,:username,:appname) returning _id";
"modified,posted,visible,username,applicationname)" +
"values (:postid,:bcontent,:modified,:posted," +
":visible,:username,:appname) returning _id";
cmd.Parameters.AddWithValue ("postid", postid);
cmd.Parameters.AddWithValue ("bcontent", content);
DateTime now = DateTime.Now;
@ -178,9 +184,10 @@ namespace Npgsql.Web.Blog
cmd.Parameters.AddWithValue ("username", from);
cmd.Parameters.AddWithValue ("appname", applicationName);
cnx.Open ();
return (long) cmd.ExecuteScalar();
return (long)cmd.ExecuteScalar ();
}
}
/// <summary>
/// Validates the comment.
/// </summary>
@ -189,6 +196,7 @@ namespace Npgsql.Web.Blog
{
throw new NotImplementedException ();
}
/// <summary>
/// Updates the comment.
/// </summary>
@ -202,6 +210,7 @@ namespace Npgsql.Web.Blog
}
private bool autoValidateComment = true;
/// <summary>
/// Gets or sets a value indicating whether this <see cref="Npgsql.Web.Blog.NpgsqlBlogProvider"/> auto validate comment.
/// </summary>
@ -211,7 +220,7 @@ namespace Npgsql.Web.Blog
return autoValidateComment;
}
set {
autoValidateComment=value;
autoValidateComment = value;
}
}
@ -227,6 +236,7 @@ namespace Npgsql.Web.Blog
}
#endregion
/// <summary>
/// Initialize the specified name and config.
/// </summary>
@ -240,10 +250,12 @@ namespace Npgsql.Web.Blog
config.Remove ("connectionStringName");
applicationName = config ["applicationName"];
config.Remove ("applicationName");
defaultPageSize = int.Parse ( config ["pageLen"] ?? "10") ;
defaultPageSize = int.Parse (config ["pageLen"] ?? "10");
base.Initialize (name, config);
}
#region implemented abstract members of BlogProvider
/// <summary>
/// Gets the post.
/// </summary>
@ -252,14 +264,14 @@ namespace Npgsql.Web.Blog
public override BlogEntry GetPost (long postid)
{
BlogEntry be = null;
using (NpgsqlConnection cnx=new NpgsqlConnection(connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand()) {
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
cmd.CommandText = "select username, title, bcontent, modified, posted, visible, photo from blog " +
"where applicationname = :appname and _id = :id";
"where applicationname = :appname and _id = :id";
cmd.Parameters.AddWithValue ("appname", applicationName);
cmd.Parameters.AddWithValue ("id", postid);
cnx.Open ();
using (NpgsqlDataReader rdr = cmd.ExecuteReader()) {
using (NpgsqlDataReader rdr = cmd.ExecuteReader ()) {
if (rdr.Read ()) {
be = new BlogEntry ();
be.Title = rdr.GetString (rdr.GetOrdinal ("title"));
@ -269,16 +281,18 @@ namespace Npgsql.Web.Blog
be.Posted = rdr.GetDateTime (rdr.GetOrdinal ("posted"));
be.Visible = rdr.GetBoolean (rdr.GetOrdinal ("visible"));
int oph = rdr.GetOrdinal ("photo");
if (!rdr.IsDBNull(oph))
if (!rdr.IsDBNull (oph))
be.Photo = rdr.GetString (oph);
be.Id = postid;
}
}
}
if (be!=null) Populate (be);
if (be != null)
Populate (be);
return be;
}
/// <summary>
/// Removes the comment.
/// </summary>
@ -292,10 +306,11 @@ namespace Npgsql.Web.Blog
cmd.CommandText = "delete from comment where _id = :id returning postid";
cmd.Parameters.AddWithValue ("id", cmtid);
cnx.Open ();
postid = (long) cmd.ExecuteScalar ();
postid = (long)cmd.ExecuteScalar ();
}
return postid;
}
/// <summary>
/// Gets the post.
/// </summary>
@ -304,13 +319,13 @@ namespace Npgsql.Web.Blog
/// <param name="title">Title.</param>
public override UUTBlogEntryCollection GetPost (string username, string title)
{
UUTBlogEntryCollection bec = new UUTBlogEntryCollection (username,title);
UUTBlogEntryCollection bec = new UUTBlogEntryCollection (username, title);
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString)) {
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
cmd.CommandText = "select _id,bcontent,modified,posted,visible,photo from blog " +
"where applicationname = :appname and username = :username and title = :title";
cmd.Parameters.AddWithValue ("appname", NpgsqlDbType.Varchar, applicationName);
cmd.Parameters.AddWithValue ("username", NpgsqlDbType.Varchar ,username);
cmd.Parameters.AddWithValue ("username", NpgsqlDbType.Varchar, username);
cmd.Parameters.AddWithValue ("title", NpgsqlDbType.Varchar, title);
cnx.Open ();
cmd.Prepare ();
@ -352,19 +367,20 @@ namespace Npgsql.Web.Blog
be.Tags = tags.ToArray ();
}
}
if (bec!=null) Populate (bec);
if (bec != null)
Populate (bec);
}
}
return bec;
}
private void SetCirclesOn(BlogEntry be)
private void SetCirclesOn (BlogEntry be)
{
List<long> circles = new List<long> ();
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString))
using (NpgsqlCommand cmdcircles = cnx.CreateCommand ()) {
cmdcircles.CommandText = "select a.circle_id from blog_access a " +
"where a.post_id = :pid";
"where a.post_id = :pid";
cmdcircles.Parameters.AddWithValue ("pid", be.Id);
cnx.Open ();
using (NpgsqlDataReader rdr = cmdcircles.ExecuteReader ()) {
@ -380,12 +396,12 @@ namespace Npgsql.Web.Blog
/// Removes the tag.
/// </summary>
/// <param name="tagid">Tagid.</param>
public override void DropTag(long tagid)
public override void DropTag (long tagid)
{
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
cmd.CommandText = "DELETE from public.tag where _id = :tid";
cmd.Parameters.AddWithValue("tagid",tagid);
cmd.Parameters.AddWithValue ("tagid", tagid);
cnx.Open ();
cmd.ExecuteNonQuery ();
cnx.Close ();
@ -393,7 +409,9 @@ namespace Npgsql.Web.Blog
}
private static string SelectTagsSql = "SELECT tag.name, tag._id FROM public.tag WHERE name like :name";
private IEnumerable<string> GetSuggestion (string pattern) {
private IEnumerable<string> GetSuggestion (string pattern)
{
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
cmd.CommandText = SelectTagsSql;
@ -402,7 +420,8 @@ namespace Npgsql.Web.Blog
}
private static string InsertTagSql = "INSERT INTO tag (name) VALUES (:name) returning _id";
private void InsertTag(long postid, long tagid)
private void InsertTag (long postid, long tagid)
{
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
@ -410,8 +429,8 @@ namespace Npgsql.Web.Blog
throw new NotImplementedException ();
}
}
private long GetTagId(string tagname)
private long GetTagId (string tagname)
{
long id = 0;
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString))
@ -419,20 +438,30 @@ namespace Npgsql.Web.Blog
cmd.CommandText = "SELECT tag._id FROM public.tag WHERE name = :name";
cmd.Parameters.AddWithValue ("name", tagname);
cnx.Open ();
id = (long) cmd.ExecuteScalar ();
id = (long)cmd.ExecuteScalar ();
}
return id;
}
private long GetOrCreateTagId(string tagname)
private long GetOrCreateTagId (string tagname)
{
long id = 0;
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
cmd.CommandText = "SELECT tag._id FROM public.tag WHERE name = :name;\n" +
"IF NOT FOUND THEN INSERT INTO tag (name) values (:name) RETURNING _id; ENDIF;\n";
cmd.Parameters.AddWithValue ("name", tagname);
cnx.Open ();
id = (long) cmd.ExecuteScalar ();
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString)) {
try {
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
cmd.CommandText = "SELECT tag._id FROM public.tag WHERE name = :name";
cmd.Parameters.AddWithValue ("name", tagname);
cnx.Open ();
id = (long)cmd.ExecuteScalar ();
}
} catch (NullReferenceException) {
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
cmd.CommandText = "INSERT INTO public.tag(name) VALUES (:name) RETURNING _id";
cmd.Parameters.AddWithValue ("name", tagname);
cnx.Open ();
id = (long)cmd.ExecuteScalar ();
}
}
}
return id;
}
@ -440,13 +469,16 @@ namespace Npgsql.Web.Blog
private static string SelectPostTagsSql = "SELECT tag.name FROM public.tag, public.tagged\n" +
"WHERE tag._id = tagged.tagid AND tagged.postid = :pid \n";
private void SetTagsOn(BlogEntryCollection bec){
"WHERE tag._id = tagged.tagid AND tagged.postid = :pid \n";
private void SetTagsOn (BlogEntryCollection bec)
{
foreach (BlogEntry be in bec) {
SetTagsOn (be);
}
}
private void SetTagsOn(BlogEntry be)
private void SetTagsOn (BlogEntry be)
{
List<string> tags = new List<string> ();
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString))
@ -464,16 +496,18 @@ namespace Npgsql.Web.Blog
}
// Assert(bec!=null);
private void Populate(BlogEntryCollection bec)
private void Populate (BlogEntryCollection bec)
{
foreach (BlogEntry be in bec) Populate(be);
foreach (BlogEntry be in bec)
Populate (be);
}
private void Populate(BlogEntry be)
private void Populate (BlogEntry be)
{
SetTagsOn (be);
SetCirclesOn (be);
}
/// <summary>
/// Post the specified username, title, content and visible.
/// </summary>
@ -482,15 +516,15 @@ namespace Npgsql.Web.Blog
/// <param name="content">Content.</param>
/// <param name="visible">If set to <c>true</c> visible.</param>
/// <param name="circles">.</param>
public override long Post (string username, string title, string content, bool visible, long [] circles)
public override long Post (string username, string title, string content, bool visible, long[] circles)
{
long pid = 0;
if (username == null)
throw new ArgumentNullException("username");
throw new ArgumentNullException ("username");
if (title == null)
throw new ArgumentNullException("title");
throw new ArgumentNullException ("title");
if (content == null)
throw new ArgumentNullException("content");
throw new ArgumentNullException ("content");
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString)) {
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
cmd.CommandText = "insert into blog (title,bcontent,modified,posted,visible,username,applicationname)" +
@ -511,12 +545,13 @@ namespace Npgsql.Web.Blog
UpdatePostCircles (pid, circles);
return pid;
}
/// <summary>
/// Updates the post photo.
/// </summary>
/// <param name="pid">Pid.</param>
/// <param name="photo">Photo.</param>
public override void UpdatePostPhoto ( long pid, string photo)
public override void UpdatePostPhoto (long pid, string photo)
{
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString)) {
cnx.Open ();
@ -530,7 +565,7 @@ namespace Npgsql.Web.Blog
}
}
private void UpdatePostCircles( long pid, long[] circles)
private void UpdatePostCircles (long pid, long[] circles)
{
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString)) {
cnx.Open ();
@ -539,21 +574,22 @@ namespace Npgsql.Web.Blog
cmd.Parameters.AddWithValue ("pid", pid);
cmd.ExecuteNonQuery ();
}
if (circles!=null)
if (circles.Length>0)
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
cmd.CommandText = "insert into blog_access (post_id,circle_id) values (:pid,:cid)";
cmd.Parameters.AddWithValue ("pid", NpgsqlTypes.NpgsqlDbType.Bigint, pid);
cmd.Parameters.Add ("cid", NpgsqlTypes.NpgsqlDbType.Bigint);
cmd.Prepare ();
foreach (long ci in circles) {
cmd.Parameters ["cid"].Value = ci;
cmd.ExecuteNonQuery ();
if (circles != null)
if (circles.Length > 0)
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
cmd.CommandText = "insert into blog_access (post_id,circle_id) values (:pid,:cid)";
cmd.Parameters.AddWithValue ("pid", NpgsqlTypes.NpgsqlDbType.Bigint, pid);
cmd.Parameters.Add ("cid", NpgsqlTypes.NpgsqlDbType.Bigint);
cmd.Prepare ();
foreach (long ci in circles) {
cmd.Parameters ["cid"].Value = ci;
cmd.ExecuteNonQuery ();
}
}
}
cnx.Close ();
}
}
/// <summary>
/// Finds the post.
/// </summary>
@ -568,40 +604,40 @@ namespace Npgsql.Web.Blog
{
BlogEntryCollection c = new BlogEntryCollection ();
totalRecords = 0;
using (NpgsqlConnection cnx=new NpgsqlConnection(connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand()) {
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
if (readersName != null) {
cmd.CommandText = "select _id, title,bcontent, modified," +
"posted,username,visible,photo " +
"from blog b left outer join " +
"(select count(*)>0 acc, a.post_id pid " +
"from blog_access a," +
" circle_members m, users u where m.circle_id = a.circle_id " +
" and m.member = u.username and u.username = :uname " +
" and u.applicationname = :appname " +
" group by a.post_id) ma on (ma.pid = b._id) " +
"where ( ((ma.acc IS NULL or ma.acc = TRUE) and b.Visible IS TRUE ) or b.username = :uname) ";
"posted,username,visible,photo " +
"from blog b left outer join " +
"(select count(*)>0 acc, a.post_id pid " +
"from blog_access a," +
" circle_members m, users u where m.circle_id = a.circle_id " +
" and m.member = u.username and u.username = :uname " +
" and u.applicationname = :appname " +
" group by a.post_id) ma on (ma.pid = b._id) " +
"where ( ((ma.acc IS NULL or ma.acc = TRUE) and b.Visible IS TRUE ) or b.username = :uname) ";
cmd.Parameters.AddWithValue ("uname", readersName);
} else {
cmd.CommandText = "select _id, title,bcontent,modified," +
"posted,username,visible,photo " +
"from blog b left outer join " +
"(select count(*)>0 acc, a.post_id pid " +
"from blog_access a" +
" group by a.post_id) ma on (ma.pid = b._id)" +
" where " +
" ma.acc IS NULL and " +
" b.Visible IS TRUE and " +
" applicationname = :appname";
"posted,username,visible,photo " +
"from blog b left outer join " +
"(select count(*)>0 acc, a.post_id pid " +
"from blog_access a" +
" group by a.post_id) ma on (ma.pid = b._id)" +
" where " +
" ma.acc IS NULL and " +
" b.Visible IS TRUE and " +
" applicationname = :appname";
}
cmd.Parameters.AddWithValue ("appname", applicationName);
if (pattern != null) {
if ((searchflags & FindBlogEntryFlags.MatchTag) > 0) {
cmd.CommandText +=
"AND EXISTS (SELECT tag._id FROM public.tag, public.tagged WHERE " +
"public.tag._id = public.tagged.tagid " +
"AND public.tagged.postid = a.post_id " +
"public.tag.name like :tagname) ";
"public.tag._id = public.tagged.tagid " +
"AND public.tagged.postid = a.post_id " +
"public.tag.name like :tagname) ";
cmd.Parameters.AddWithValue ("tagname", pattern);
}
@ -624,11 +660,11 @@ namespace Npgsql.Web.Blog
cmd.CommandText += " order by posted desc";
cnx.Open ();
using (NpgsqlDataReader rdr = cmd.ExecuteReader()) {
using (NpgsqlDataReader rdr = cmd.ExecuteReader ()) {
// pageIndex became one based
int firstrec = pageIndex * pageSize;
int lastrec = firstrec + pageSize - 1;
while (rdr.Read()) {
while (rdr.Read ()) {
if (totalRecords >= firstrec && totalRecords <= lastrec) {
BlogEntry be = new BlogEntry ();
be.Title = rdr.GetString (rdr.GetOrdinal ("title"));
@ -637,7 +673,7 @@ namespace Npgsql.Web.Blog
be.Author = rdr.GetString (rdr.GetOrdinal ("username"));
be.Posted = rdr.GetDateTime (rdr.GetOrdinal ("posted"));
be.Modified = rdr.GetDateTime (rdr.GetOrdinal ("modified"));
be.Visible = rdr.GetBoolean (rdr.GetOrdinal ("visible"));
be.Visible = rdr.GetBoolean (rdr.GetOrdinal ("visible"));
{
int oph = rdr.GetOrdinal ("photo");
if (!rdr.IsDBNull (oph))
@ -650,10 +686,12 @@ namespace Npgsql.Web.Blog
rdr.Close ();
}
}
if (c!=null) Populate (c);
if (c != null)
Populate (c);
return c;
}
/// <summary>
/// Removes the post.
/// </summary>
@ -661,20 +699,21 @@ namespace Npgsql.Web.Blog
/// <param name="title">Title.</param>
public override void RemoveTitle (string username, string title)
{
using (NpgsqlConnection cnx=new NpgsqlConnection(connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand()) {
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
cmd.CommandText = "delete from blog where username = :username and applicationname = :appname and title=:title";
cmd.Parameters.AddWithValue ("username",username);
cmd.Parameters.AddWithValue ("username", username);
cmd.Parameters.AddWithValue ("appname", applicationName);
cmd.Parameters.AddWithValue ("title",title);
cmd.Parameters.AddWithValue ("title", title);
cnx.Open ();
cmd.ExecuteNonQuery ();
cnx.Close();
cnx.Close ();
}
}
int defaultPageSize = 10;
/// <summary>
/// Lasts the posts.
/// </summary>
@ -682,23 +721,23 @@ namespace Npgsql.Web.Blog
/// <param name="pageIndex">Page index.</param>
/// <param name="pageSize">Page size.</param>
/// <param name="totalRecords">Total records.</param>
public override BlogEntryCollection LastPosts(int pageIndex, int pageSize, out int totalRecords)
public override BlogEntryCollection LastPosts (int pageIndex, int pageSize, out int totalRecords)
{
BlogEntryCollection c = new BlogEntryCollection ();
using (NpgsqlConnection cnx=new NpgsqlConnection(connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand()) {
using (NpgsqlConnection cnx = new NpgsqlConnection (connectionString))
using (NpgsqlCommand cmd = cnx.CreateCommand ()) {
cmd.CommandText = "select * " +
"from blog where applicationname = :appname and visible = true " +
" order by posted desc limit :len" ;
"from blog where applicationname = :appname and visible = true " +
" order by posted desc limit :len";
cmd.Parameters.AddWithValue ("appname", applicationName);
cmd.Parameters.AddWithValue ("len", defaultPageSize*10);
cmd.Parameters.AddWithValue ("len", defaultPageSize * 10);
cnx.Open ();
using (NpgsqlDataReader rdr = cmd.ExecuteReader()) {
using (NpgsqlDataReader rdr = cmd.ExecuteReader ()) {
totalRecords = 0;
int firstrec = pageIndex * pageSize;
int lastrec = firstrec + pageSize - 1;
while (rdr.Read()) {
while (rdr.Read ()) {
if (totalRecords >= firstrec && totalRecords <= lastrec) {
BlogEntry be = new BlogEntry ();
be.Id = rdr.GetInt64 (rdr.GetOrdinal ("_id"));
@ -719,9 +758,11 @@ namespace Npgsql.Web.Blog
}
}
}
if (c!=null) Populate (c);
if (c != null)
Populate (c);
return c;
}
#endregion
}
}

@ -1,5 +1,5 @@
//
// NUnitTestClass.cs
//
// AllTests.cs
//
// Author:
// Paul Schneider <paul@pschneider.fr>
@ -18,24 +18,35 @@
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using NUnit.Framework;
using System;
using Yavsc.Model.Blogs;
using Yavsc.Controllers;
using System.Web.Mvc;
using System.Web.Security;
using System.Web.Configuration;
using System.Configuration;
using System.IO;
using System.Web.Http;
using Mono.WebServer;
using System.Net;
using System.Collections;
namespace Yavsc
{
/// <summary>
/// N unit test class.
/// </summary>
[TestFixture ()]
public class NUnitTestClass
public class AllTests
{
/// <summary>
/// Tests the case.
/// </summary>
[Test ()]
public void TestCase ()
[Suite]
public static IEnumerable Suite
{
get
{
ArrayList suite = new ArrayList ();
suite.Add(new BlogUnitTestCase());
return suite;
}
}
}
}

@ -25,7 +25,7 @@ using Yavsc.Model.Blogs;
namespace Yavsc
{
[TestFixture ()]
public class BlogUnitTestCase: AccountUnitTestCase
public class BlogUnitTestCase: ServerTestCase
{
[TestFixtureSetUp]

@ -0,0 +1,11 @@
2015-10-17 Paul Schneider <paul@pschneider.fr>
* AllTests.cs:
* HelloWorld.cs:
* DebugServer.cs:
* TestAPI.csproj:
* TestAutomate.cs:
* ServerTestCase.cs:
* BlogUnitTestCase.cs:
* test-domain-TestAPI.config:

@ -1,5 +1,5 @@
//
// parralax.js
//
// DebugServer.cs
//
// Author:
// Paul Schneider <paul@pschneider.fr>
@ -19,19 +19,33 @@
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
$(document).ready(function(){
var $window = $(window);
$(window).scroll(function() {
var $ns = $('#notifications');
if ($ns.has('*').length>0) {
if ($window.scrollTop()>375) {
$ns.css('position','fixed');
$ns.css('z-index',2);
$ns.css('top',0);
using System;
using NUnit.Framework;
using System.Net;
using Mono.WebServer.XSP;
namespace Mono.WebServer.Test
{
public class DebugServer : IDisposable
{
#region IDisposable implementation
public void Dispose ()
{
// would have a sense when managing the Xsp server instance:
// server.Stop();
}
#endregion
string physicalPath = @"/home/paul/workspace/totem/web/";
public int Run ()
{
return Server.Main (new [] { "--applications", "/:"+physicalPath, "--port", "8080", "--nonstop" });
}
else {
$ns.css('position','static');
$ns.css('z-index',1);
}}
});
});
}
}

@ -0,0 +1,73 @@
//
// HelloWorld.cs
//
//
// HelloWorld.cs
//
// Author:
// Leonardo Taglialegne <leonardo.taglialegne@gmail.com>
//
// Copyright (c) 2013 Leonardo Taglialegne.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using NUnit.Framework;
using System.Net;
using Mono.WebServer.XSP;
namespace Mono.WebServer.Test
{
[TestFixture]
public class HelloWorld
{
[Test]
public void TestCase ()
{
using (var server = new DebugServer()) {
Assert.AreEqual (0, server.Run ());
var wc = new WebClient ();
try {
string downloaded = wc.DownloadString ("http://localhost:8080/");
//Assert.AreEqual (Environment.CurrentDirectory, downloaded);
// ResponseHeaders {
// Date: Thu, 15 Oct 2015 16:12:00 GMT
// Server: Mono.WebServer.XSP/3.8.0.0 Linux
// X-AspNetMvc-Version: 3.0
// X-AspNet-Version: 4.0.30319
// Content-Length: 2180
// Cache-Control: private
// Content-Type: text/html
// Set-Cookie: ASP.NET_SessionId=ED208D636A4312B9745E396D; path=/
// Keep-Alive: timeout=15, max=100
// Connection: Keep-Alive } System.Net.WebHeaderCollection
Assert.Greater(wc.ResponseHeaders["Set-Cookie"].Length, 10);
} catch (WebException e) {
Assert.Fail (e.Message);
}
}
}
}
}

@ -28,12 +28,17 @@ using System.Web.Configuration;
using System.Configuration;
using System.IO;
using System.Web.Http;
using Mono.WebServer;
using System.Net;
using System.Web.Hosting;
using Mono.Web.Util;
using Mono.WebServer.Options;
namespace Yavsc
{
[TestFixture ()]
public class AccountUnitTestCase
public class ServerTestCase
{
public string UserName { get; set; }
@ -47,33 +52,70 @@ namespace Yavsc
return accountController;
}
}
ApplicationServer WebAppServer;
string defaultMembershipProvider = null;
[Test]
public virtual void Init()
public virtual void Start()
{
webSource = new XSPWebSource (configurationManager.Address, configurationManager.Port, !root);
// get the web config
string physicalPath = @"/home/paul/workspace/totem/web/";
string physicalPathToConfig = physicalPath + "/Web.config";
ExeConfigurationFileMap exemap = new ExeConfigurationFileMap ();
exemap.ExeConfigFilename = physicalPathToConfig ;
Configuration config = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration (exemap, ConfigurationUserLevel.None);
var server = new ApplicationServer (webSource, configurationManager.Root) {
Verbose = configurationManager.Verbose,
SingleApplication = !root
};
string basedir = AppDomain.CurrentDomain.BaseDirectory;
string curdir = Directory.GetCurrentDirectory ();
string dummyVirtualPath = "/";
string physicalPath = @"/home/paul/workspace/totem/web/";
WebConfigurationFileMap map = new WebConfigurationFileMap ();
map.VirtualDirectories.Add(dummyVirtualPath, new VirtualDirectoryMapping(physicalPath, true));
Configuration configuration = WebConfigurationManager.OpenMappedWebConfiguration(map, dummyVirtualPath);
accountController = new AccountController ();
string da = (string) configuration.AppSettings.Settings ["DefaultAvatar"].Value;
MembershipSection s = configuration.GetSection ("system.web/membership") as MembershipSection;
defaultMembershipProvider = s.DefaultProvider;
int Port=8080;
XSPWebSource websource=new XSPWebSource(IPAddress.Any,Port);
WebAppServer=new ApplicationServer(websource,physicalPath);
var broker = new XSPRequestBroker ();
var host = new XSPApplicationHost ();
host.RequestBroker = broker;
host.Server = WebAppServer;
broker.InitializeLifetimeService ();
host.InitializeLifetimeService ();
// ApplicationHost h = new XSPApplicationHost();
//"[[hostname:]port:]VPath:realpath"
string cmdLine=Port+":/:"+physicalPath;
WebAppServer.AddApplicationsFromCommandLine (cmdLine);
WebAppServer.Broker = broker;
WebAppServer.AppHost = host;
// WebAppServer.AddApplicationsFromConfigFile (physicalPath+"/Web.config");
// WebConfigurationFileMap map = new WebConfigurationFileMap ();
// map.VirtualDirectories.Add (dummyVirtualPath, new VirtualDirectoryMapping (physicalPath, true));
// TODO why not? Configuration configuration = WebConfigurationManager.OpenMappedWebConfiguration (map, dummyVirtualPath);
// string da = (string)config.AppSettings.Settings ["DefaultAvatar"].Value;
// MembershipSection s = config.GetSection ("system.web/membership") as MembershipSection;
// defaultMembershipProvider = s.DefaultProvider;
// ??? WebConfigurationManager.ConfigPath
Configuration cfg = WebConfigurationManager.OpenWebConfiguration (dummyVirtualPath);
// WebConfigurationManager.AppSettings.Clear ();
// WebConfigurationManager.ConnectionStrings.Clear ();
// var mbrssect = WebConfigurationManager.GetWebApplicationSection ("system.web/membership") as MembershipSection;
//
// mbrssect.Providers.Clear ();
var syswebcfg = WebConfigurationManager.GetWebApplicationSection ("system.web") as ConfigurationSection;
WebAppServer.Start (true,2000);
// System.Threading.Thread.Sleep(30000);
}
[Test ()]
public virtual void Register ()
{
accountController = new AccountController ();
ViewResult actionResult = accountController.Register (
new Yavsc.Model.RolesAndMembers.RegisterViewModel () {
UserName = UserName, Email = Email,
@ -93,7 +135,11 @@ namespace Yavsc
Assert.True (u.IsApproved);
}
[TestFixtureTearDown()]
[Test()]
public virtual void Stop() {
WebAppServer.Stop();
}
public virtual void Unregister()
{
ViewResult actionResult =

@ -58,11 +58,37 @@
<Reference Include="System.Web.Mvc" />
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.Web" />
<Reference Include="System.Configuration" />
<Reference Include="System.Web.Routing" />
<Reference Include="System.Web.Http" />
<Reference Include="System.Web.Abstractions" />
<Reference Include="System.Security" />
<Reference Include="System.Net" />
<Reference Include="Mono.WebServer2">
<HintPath>..\..\..\..\..\usr\lib\mono\4.5\Mono.WebServer2.dll</HintPath>
</Reference>
<Reference Include="xsp4">
<HintPath>..\..\..\..\..\usr\lib\mono\4.5\xsp4.exe</HintPath>
</Reference>
<Reference Include="nunit.util, Version=2.6.3.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
<Package>nunit</Package>
</Reference>
<Reference Include="nunit.mocks, Version=2.6.3.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
<Package>nunit</Package>
</Reference>
<Reference Include="nunit-console-runner, Version=2.6.3.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
<Package>nunit</Package>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TestAutomate.cs" />
<Compile Include="BlogUnitTest.cs" />
<Compile Include="BlogUnitTestCase.cs" />
<Compile Include="TestByteA.cs" />
<Compile Include="AllTests.cs" />
<Compile Include="HelloWorld.cs" />
<Compile Include="ServerTestCase.cs" />
<Compile Include="DebugServer.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@ -74,8 +100,28 @@
<Project>{77044C92-D2F1-45BD-80DD-AA25B311B027}</Project>
<Name>Web</Name>
</ProjectReference>
<ProjectReference Include="..\NpgsqlBlogProvider\NpgsqlBlogProvider.csproj">
<Project>{C6E9E91B-97D3-48D9-8AA7-05356929E162}</Project>
<Name>NpgsqlBlogProvider</Name>
</ProjectReference>
<ProjectReference Include="..\NpgsqlContentProvider\NpgsqlContentProvider.csproj">
<Project>{821FF72D-9F4B-4A2C-B95C-7B965291F119}</Project>
<Name>NpgsqlContentProvider</Name>
</ProjectReference>
<ProjectReference Include="..\NpgsqlMRPProviders\NpgsqlMRPProviders.csproj">
<Project>{BBA7175D-7F92-4278-96FC-84C495A2B5A6}</Project>
<Name>NpgsqlMRPProviders</Name>
</ProjectReference>
<ProjectReference Include="..\SalesCatalog\SalesCatalog.csproj">
<Project>{90BF2234-7252-4CD5-B2A4-17501B19279B}</Project>
<Name>SalesCatalog</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="test-domain-TestAPI.config">
<Gettext-ScanForTranslations>False</Gettext-ScanForTranslations>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
</Project>

@ -55,7 +55,9 @@ namespace TestAPI
[Test]
public void DoTheTest()
{
// Establish
context.Invoke ();
// Because
of.Invoke ();
should_be_in_state_0.Invoke ();
should_not_be_in_state_1.Invoke ();

@ -21,38 +21,38 @@ namespace Yavsc.ApiControllers
/// </summary>
public class BlogsController : YavscApiController
{
private const string adminRoleName = "Admin";
/// <summary>
/// Initialize the specified controllerContext.
/// Tag the specified postid and tag.
/// </summary>
/// <param name="controllerContext">Controller context.</param>
protected override void Initialize (System.Web.Http.Controllers.HttpControllerContext controllerContext)
{
base.Initialize (controllerContext);
if (!Roles.RoleExists (adminRoleName)) {
Roles.CreateRole (adminRoleName);
/// <param name="id">Postid.</param>
/// <param name="tag">Tag.</param>
[Authorize,
AcceptVerbs ("POST")]
public void Tag (PostTag model) {
if (ModelState.IsValid) {
BlogManager.GetForEditing (model.PostId);
BlogManager.Tag (model.PostId, model.Tag);
}
}
/// <summary>
/// Tag the specified postid and tag.
/// <summary>
/// Tags the specified pattern.
/// </summary>
/// <param name="postid">Postid.</param>
/// <param name="tag">Tag.</param>
public void Tag (long postid,string tag) {
BlogManager.GetForEditing (postid);
BlogManager.Tag (postid, tag);
/// <param name="pattern">Pattern.</param>
[ValidateAjaxAttribute]
public IEnumerable<string> Tags(string pattern)
{
return new string[] { "Artistes", "Accueil", "Mentions juridique", "Admin", "Web" } ;
}
/// <summary>
/// Untag the specified postid and tag.
/// </summary>
/// <param name="postid">Postid.</param>
/// <param name="id">Postid.</param>
/// <param name="tag">Tag.</param>
public void Untag (long postid,string tag) {
BlogManager.GetForEditing (postid);
BlogManager.Untag (postid, tag);
[Authorize, ValidateAjaxAttribute, HttpPost]
public void Untag (long id, [FromBody] string tag) {
BlogManager.GetForEditing (id);
BlogManager.Untag (id, tag);
}
/// <summary>
@ -60,8 +60,8 @@ namespace Yavsc.ApiControllers
/// </summary>
/// <param name="user">User.</param>
/// <param name="title">Title.</param>
[Authorize]
public void RemoveTitle(string user, string title) {
[Authorize, ValidateAjaxAttribute, HttpPost]
public void RemoveTitle(string user, string title) {
if (Membership.GetUser ().UserName != user)
if (!Roles.IsUserInRole("Admin"))
throw new AuthorizationDenied (user);
@ -72,7 +72,8 @@ namespace Yavsc.ApiControllers
/// Removes the tag.
/// </summary>
/// <param name="tagid">Tagid.</param>
public void RemoveTag(long tagid) {
[Authorize, ValidateAjaxAttribute, HttpPost]
public void RemoveTag([FromBody] long tagid) {
throw new NotImplementedException ();
}
@ -96,7 +97,7 @@ namespace Yavsc.ApiControllers
/// Posts the file.
/// </summary>
/// <returns>The file.</returns>
[Authorize,HttpPost]
[Authorize, HttpPost]
public async Task<HttpResponseMessage> PostFile(long id) {
if (!(Request.Content.Headers.ContentType.MediaType=="multipart/form-data"))
throw new HttpRequestException ("not a multipart/form-data request");
@ -142,10 +143,10 @@ namespace Yavsc.ApiControllers
/// Searchs the file.
/// </summary>
/// <returns>The file.</returns>
/// <param name="postid">Postid.</param>
/// <param name="id">Postid.</param>
/// <param name="terms">Terms.</param>
[Authorize,HttpGet]
public async Task<HttpResponseMessage> SearchFile(long postid, string terms) {
[HttpGet]
public async Task<HttpResponseMessage> SearchFile(long id, string terms) {
throw new NotImplementedException ();
}
@ -154,8 +155,8 @@ namespace Yavsc.ApiControllers
/// </summary>
/// <param name="id">Identifier.</param>
/// <param name="photo">Photo.</param>
[Authorize,HttpPost]
public void SetPhoto(long id, string photo)
[Authorize, HttpPost, ValidateAjaxAttribute]
public void SetPhoto(long id, [FromBody] string photo)
{
BlogManager.Provider.UpdatePostPhoto (id, photo);
}
@ -164,6 +165,7 @@ namespace Yavsc.ApiControllers
/// Import the specified id.
/// </summary>
/// <param name="id">Identifier.</param>
[Authorize, HttpPost, ValidateAjaxAttribute]
public async Task<HttpResponseMessage> Import(long id) {
if (!(Request.Content.Headers.ContentType.MediaType=="multipart/form-data"))
throw new HttpRequestException ("not a multipart/form-data request");

@ -7,24 +7,53 @@ body {
padding: 0;
margin: 0;
}
/* Start by setting display:none to make this hidden.
Then we position it in relation to the viewport window
with position:fixed. Width, height, top and left speak
for themselves. Background we set to 80% white with
our animation centered, and no-repeating */
.modal {
display: none;
position: fixed;
z-index: 1000;
top: 0;
left: 0;
height: 100%;
width: 100%;
background: rgba( 255, 255, 255, .8 )
url('http://i.stack.imgur.com/FhHRx.gif')
50% 50%
no-repeat;
}
/* When the body has the loading class, we turn
the scrollbar off with overflow:hidden */
body.loading {
overflow: hidden;
}
/* Anytime the body has the loading class, our
modal element will be visible */
body.loading .modal {
display: block;
}
.iconsmall { max-height: 1.3em; max-width: 1.3em; }
.photo { width: 100%; }
.blogbanner { float: left; top:0; }
.subtitle { font-size:small; font-style: italic; }
header {
padding: 0;
margin: 0;
margin-top: 0;
padding-top: 201px;
margin-bottom:2em;
padding-bottom:2em;
display: block;
text-align: center;
background: url("/images/totem-banner.xs.jpg") 0 0 no-repeat fixed;
}
header h1, header a {
background-color: rgba(0,0,0,.5);
margin:0; padding:1em;
}
nav {
@ -34,12 +63,11 @@ nav {
border-radius:1em;
background: url("/images/live-concert-388160_1280.jpg") 50% 10em repeat fixed ;
justify-content: space-around;
min-height:5em;
}
main {
margin: 2em;
padding: 6em 2em 6em 2em;
padding: 2em;
display: block;
border-radius:1em;
background: url("/images/musician-923526_1.nbb.jpg") 50% 20em repeat fixed ;
@ -54,29 +82,26 @@ footer {
clear: both;
font-size: smaller;
justify-content: space-around;
}
footer a {
border-radius:5px;
margin:.5em;
border-radius:1em;
padding:1em;
}
legend {
border-radius:5px;
margin:.5em;
padding:1.5em;
padding:.5em;
background-color: rgba(0,0,32,.5);
}
#copyr { text-align: center; display: block; background-color: rgba(20,20,20,.8); }
footer p { display:inline-block; }
footer img { max-height: 2em; vertical-align: middle; }
footer img { max-height: 3em; vertical-align: middle; }
a img, h1 img, .menuitem img { max-height: 1em; vertical-align: middle; }
#gspacer {
background-color: rgba(20,20,20,.8);
border-radius:5px;
margin:.5em; padding:1em; display: inline-block }
border-radius:1em;
margin:1em; padding:1em; display: inline-block }
fieldset {
background-color: rgba(16,16,64,0.8);
border-radius:5px; border: solid 1px #000060;
@ -85,7 +110,7 @@ fieldset {
main video, main img {
max-width:100%;
max-height:75%;
padding: .5em;
padding: 1em;
}
aside {
@ -97,10 +122,9 @@ aside {
.postpreview {
display: inline-block;
max-width: 40em;
padding: .5em;
margin: .5em;
padding: 1em;
background-color: rgba(0,0,32,0.8);
border-radius:10px;
border-radius:1em;
}
.postpreview video, .postpreview img {
max-width:100%;
@ -108,11 +132,10 @@ aside {
}
.post {
display:block;
margin:1em;
padding:1em;
padding: 1em;
background-color: rgba(0,0,32,0.8);
color: #eee;
border-radius:10px;
border-radius:1em;
}
.hiddenpost { background-color: rgba(16,16,16,0.5); }
.fullwidth { width: 100%; }
@ -129,24 +152,23 @@ textarea.fullwidth { min-height:10em; }
.panel,.bshpanel, aside {
background-color: rgba(20,20,20,.8);
border-radius: 5px;
margin: .5em;
padding: .5em;
border-radius: 1em;
padding: 1em;
}
.spanel {
max-width: 24em;
display: inline-block;
margin: .3em;
padding: .3em;
}
.xspanel {
max-width:13em;
display: inline-block;
margin:.2em;
padding:.2em;
}
.xxspanel {
max-width:7em;
display: inline-block;
margin:.1em;
padding:.1em;
}
.hint {
display: inline;
@ -162,7 +184,7 @@ content: ")";
.usertitleref {
border-radius: 5px;
border-radius: 1em;
background-color:rgba(0,0,32,0.6);
font-family: 'Arial', cursive;
padding: 1em;
@ -180,8 +202,7 @@ label {
border: dashed rgb(020,20,256) 2px;
}
#notifications {
margin: 2em;
padding: 2em;
padding: 1em;
}
.notification {
@ -230,7 +251,6 @@ a {
cursor: pointer;
font-family: 'Arial', cursive;
padding: 1em;
margin:1em;
}
input, select, textarea {
@ -299,22 +319,33 @@ input, select, textarea {
.c3-alt { display:none; }
@media all and (max-width: 640px) {
header {
padding-bottom:1em;
}
header h1, header a , .actionlink, .menuitem, a { padding:.5em;}
nav {
margin: 1em;
margin: 1em;
padding: 1em;
min-height:4em;
background: url("/images/live-concert-388160_1280.s.jpg") 50% 10% repeat fixed ;
}
main {
margin: 1em;
padding: 4em 1em 4em 1em;
margin: 1em;
padding: 1em;
background: url("/images/musician-923526_1.nbb.xs.jpg") 50% 20em repeat fixed ;
}
footer {
background: url("/images/drummer-652345_1280.xs.jpg") 50% 90% repeat fixed ;
padding: 1em;
margin: 1em;
background: url("/images/drummer-652345_1280.s.jpg") 50% 90% repeat fixed ;
}
footer a {
border-radius:.5em;
margin:.5em;
padding:.5em;
}
#notifications {
padding: .5em;
}
.menuitem {
display: block;
}
@ -326,7 +357,6 @@ input, select, textarea {
padding:.3em;
}
.bshpanel { cursor:zoom-in; }
footer { clear:both; }
.c2 { display:initial; }
.c2-alt { display:none; }
@ -336,30 +366,30 @@ input, select, textarea {
@media all and (max-width: 350px) {
header {
padding: 0;
margin: 0;
margin-top: 0;
padding-top: 101px;
margin-bottom:1em;
padding-bottom:1em;
background: url("/images/totem-banner.xxs.jpg") 0 0 no-repeat fixed;
}
header h1, header a { padding:.2em;}
nav {
margin: .5em;
margin: .5em;
padding: .5em;
min-height:3em;
background: url("/images/live-concert-388160_1280.xxs.jpg") 50% 10% repeat fixed ;
}
main {
margin: .5em;
padding: 3em .5em 3em .5em;
margin: .5em;
padding: .5em;
background: url("/images/musician-923526_1.nbb.xxs.jpg") 50% 20em repeat fixed ;
}
footer {
background: url("/images/drummer-652345_1280.xxs.jpg") 50% 90% repeat fixed ;
margin: 0.5em;
padding: 0.5em;
}
footer a {
border-radius:.2em;
margin:.2em;
padding:.2em;
}
.c2 { display:none; }
.c2-alt { display:initial; }
}

@ -1,3 +1,29 @@
2015-10-17 Paul Schneider <paul@pschneider.fr>
* Web.csproj:
* Global.asax.cs:
* yavsc.js:
* App.master:
* style.css:
* Edit.aspx:
* Title.aspx:
* Index.aspx:
* YavscHelpers.cs:
* UserPost.aspx:
* UserPosts.aspx:
* PageLinks.ascx:
* TagControl.ascx:
* PostActions.ascx:
* HomeController.cs:
* AdminController.cs:
* BlogsController.cs:
* GoogleController.cs:
* Estimate.aspx:
* AccountController.cs:
* BlogsController.cs:
* knockout-jqAutocomplete.js:
* knockout-jqAutocomplete.min.js:
2015-10-13 Paul Schneider <paul@pschneider.fr>
* Index.aspx:

@ -388,20 +388,20 @@ namespace Yavsc.Controllers
{
MembershipUser u = Membership.GetUser (id, false);
if (u == null) {
ViewData ["Error"] =
string.Format ("Cet utilisateur n'existe pas ({0})", id);
YavscHelpers.Notify( ViewData,
string.Format ("Cet utilisateur n'existe pas ({0})", id));
} else if (u.ProviderUserKey.ToString () == key) {
if (u.IsApproved) {
ViewData ["Message"] =
string.Format ("Votre compte ({0}) est déjà validé.", id);
YavscHelpers.Notify( ViewData,
string.Format ("Votre compte ({0}) est déjà validé.", id));
} else {
u.IsApproved = true;
Membership.UpdateUser (u);
ViewData ["Message"] =
string.Format ("La création de votre compte ({0}) est validée.", id);
YavscHelpers.Notify( ViewData,
string.Format ("La création de votre compte ({0}) est validée.", id));
}
} else
ViewData ["Error"] = "La clé utilisée pour valider ce compte est incorrecte";
YavscHelpers.Notify( ViewData, "La clé utilisée pour valider ce compte est incorrecte" );
return View ();
}

@ -165,7 +165,7 @@ namespace Yavsc.Controllers
ViewData ["usertoremove"] = username;
if (submitbutton == "Supprimer") {
Membership.DeleteUser (username);
YavscHelpers.Notice(ViewData, string.Format("utilisateur \"{0}\" supprimé",username));
YavscHelpers.Notify(ViewData, string.Format("utilisateur \"{0}\" supprimé",username));
ViewData ["usertoremove"] = null;
}
return View ();
@ -240,7 +240,7 @@ namespace Yavsc.Controllers
public ActionResult DoAddRole (string rolename)
{
Roles.CreateRole(rolename);
YavscHelpers.Notice(ViewData, LocalizedText.role_created+ " : "+rolename);
YavscHelpers.Notify(ViewData, LocalizedText.role_created+ " : "+rolename);
return View ();
}
@ -278,7 +278,7 @@ namespace Yavsc.Controllers
ViewData ["useritems"] = users;
if (ModelState.IsValid) {
Roles.AddUserToRole (model.UserName, adminRoleName);
YavscHelpers.Notice(ViewData, model.UserName + " "+LocalizedText.was_added_to_the_role+" '" + adminRoleName + "'");
YavscHelpers.Notify(ViewData, model.UserName + " "+LocalizedText.was_added_to_the_role+" '" + adminRoleName + "'");
} else {
if (admins.Length > 0) {
if (! admins.Contains (Membership.GetUser ().UserName)) {
@ -290,7 +290,7 @@ namespace Yavsc.Controllers
// No admin, gives the Admin Role to the current user
Roles.AddUserToRole (currentUser, adminRoleName);
admins = new string[] { currentUser };
YavscHelpers.Notice(ViewData, string.Format (
YavscHelpers.Notify(ViewData, string.Format (
LocalizedText.was_added_to_the_empty_role,
currentUser, adminRoleName));
}

@ -36,8 +36,11 @@ namespace Yavsc.Controllers
/// <param name="title">Title.</param>
/// <param name="pageIndex">Page index.</param>
/// <param name="pageSize">Page size.</param>
public ActionResult Index (int pageIndex = 0, int pageSize = 10)
public ActionResult Index (string title, int pageIndex = 0, int pageSize = 10)
{
if (title != null)
return Title (title, pageIndex, pageSize);
return BlogList (pageIndex, pageSize);
}
/// <summary>
@ -45,7 +48,7 @@ namespace Yavsc.Controllers
/// </summary>
/// <returns>The media.</returns>
/// <param name="id">Identifier.</param>
public ActionResult ChooseMedia(long id)
public ActionResult ChooseMedia(long postid)
{
return View ();
}
@ -76,20 +79,20 @@ namespace Yavsc.Controllers
/// <param name="pageSize">Page size.</param>
///
[HttpGet]
public ActionResult Title (string id, int pageIndex = 0, int pageSize = 10)
public ActionResult Title (string title, int pageIndex = 0, int pageSize = 10)
{
int recordCount;
MembershipUser u = Membership.GetUser ();
string username = u == null ? null : u.UserName;
FindBlogEntryFlags sf = FindBlogEntryFlags.MatchTitle;
BlogEntryCollection c =
BlogManager.FindPost (username, id, sf, pageIndex, pageSize, out recordCount);
var utc = new UTBlogEntryCollection (id);
BlogManager.FindPost (username, title, sf, pageIndex, pageSize, out recordCount);
var utc = new UTBlogEntryCollection (title);
utc.AddRange (c);
ViewData ["RecordCount"] = recordCount;
ViewData ["PageIndex"] = pageIndex;
ViewData ["PageSize"] = pageSize;
return View (utc);
return View ("Title", utc);
}
/// <summary>
@ -100,27 +103,30 @@ namespace Yavsc.Controllers
/// <param name="pageIndex">Page index.</param>
/// <param name="pageSize">Page size.</param>
[HttpGet]
public ActionResult UserPosts (string id, int pageIndex = 0, int pageSize = 10)
public ActionResult UserPosts (string user, string title=null, int pageIndex = 0, int pageSize = 10)
{
if (title != null) return UserPost (user, title, pageIndex, pageSize);
int recordcount=0;
MembershipUser u = Membership.GetUser ();
FindBlogEntryFlags sf = FindBlogEntryFlags.MatchUserName;
ViewData ["SiteName"] = sitename;
ViewData ["BlogUser"] = id;
ViewData ["BlogUser"] = user;
string readersName = null;
ViewData ["PageIndex"] = pageIndex;
ViewData ["pageSize"] = pageSize;
// displays invisible items when the logged user is also the author
if (u != null) {
if (u.UserName == id || Roles.IsUserInRole ("Admin"))
if (u.UserName == user || Roles.IsUserInRole ("Admin"))
sf |= FindBlogEntryFlags.MatchInvisible;
readersName = u.UserName;
if (user == null)
user = u.UserName;
}
// find entries
BlogEntryCollection c =
BlogManager.FindPost (readersName, id, sf, pageIndex, pageSize, out recordcount);
BlogManager.FindPost (readersName, user, sf, pageIndex, pageSize, out recordcount);
// Get author's meta data
var pr = ProfileBase.Create (id);
var pr = ProfileBase.Create (user);
if (pr != null) {
Profile bupr = new Profile (pr);
ViewData ["BlogUserProfile"] = bupr;
@ -130,7 +136,7 @@ namespace Yavsc.Controllers
ViewData ["Avatar"] = bupr.avatar;
}
ViewData ["RecordCount"] = recordcount;
UUBlogEntryCollection uuc = new UUBlogEntryCollection (id, c);
UUBlogEntryCollection uuc = new UUBlogEntryCollection (user, c);
return View ("UserPosts", uuc);
}
@ -147,14 +153,14 @@ namespace Yavsc.Controllers
}
/// <summary>
/// Returns the post.
/// Gets the post.
/// </summary>
/// <returns>The post.</returns>
/// <param name="id">Identifier.</param>
public ActionResult GetPost (long id)
/// <param name="postid">Postid.</param>
public ActionResult GetPost (long postid)
{
ViewData ["id"] = id;
BlogEntry e = BlogManager.GetForReading (id);
ViewData ["id"] = postid;
BlogEntry e = BlogManager.GetForReading (postid);
UUTBlogEntryCollection c = new UUTBlogEntryCollection (e.Author,e.Title);
c.Add (e);
ViewData ["user"] = c.Author;
@ -306,15 +312,15 @@ namespace Yavsc.Controllers
/// </summary>
/// <param name="id">Identifier.</param>
[Authorize]
public ActionResult Edit (long id)
public ActionResult Edit (long postid)
{
BlogEntry e = BlogManager.GetForEditing (id);
BlogEntry e = BlogManager.GetForEditing (postid);
string user = Membership.GetUser ().UserName;
Profile pr = new Profile (ProfileBase.Create(e.Author));
ViewData ["BlogTitle"] = pr.BlogTitle;
ViewData ["LOGIN"] = user;
ViewData ["Id"] = id;
ViewData ["Id"] = postid;
// Populates the circles combo items
if (e.AllowedCircles == null)
@ -356,21 +362,21 @@ namespace Yavsc.Controllers
/// <param name="returnUrl">Return URL.</param>
/// <param name="confirm">If set to <c>true</c> confirm.</param>
[Authorize]
public ActionResult RemoveTitle (string id, string user, string returnUrl, bool confirm = false)
public ActionResult RemoveTitle (string user, string title, string returnUrl, bool confirm = false)
{
if (returnUrl == null)
if (Request.UrlReferrer != null)
returnUrl = Request.UrlReferrer.AbsoluteUri;
ViewData ["returnUrl"] = returnUrl;
ViewData ["Author"] = user;
ViewData ["Title"] = id;
ViewData ["Title"] = title;
if (Membership.GetUser ().UserName != user)
if (!Roles.IsUserInRole("Admin"))
throw new AuthorizationDenied (user);
if (!confirm)
return View ("RemoveTitle");
BlogManager.RemoveTitle (user, id);
BlogManager.RemoveTitle (user, title);
if (returnUrl == null)
RedirectToAction ("Index", new { user = user });
return Redirect (returnUrl);
@ -384,19 +390,19 @@ namespace Yavsc.Controllers
/// <param name="returnUrl">Return URL.</param>
/// <param name="confirm">If set to <c>true</c> confirm.</param>
[Authorize]
public ActionResult RemovePost (long id, string returnUrl, bool confirm = false)
public ActionResult RemovePost (long postid, string returnUrl, bool confirm = false)
{
// ensures the access control
BlogEntry e = BlogManager.GetForEditing (id);
BlogEntry e = BlogManager.GetForEditing (postid);
if (e == null)
return new HttpNotFoundResult ("post id "+id.ToString());
ViewData ["id"] = id;
return new HttpNotFoundResult ("post id "+postid.ToString());
ViewData ["id"] = postid;
ViewData ["returnUrl"] = string.IsNullOrWhiteSpace(returnUrl)?
Request.UrlReferrer.AbsoluteUri.ToString(): returnUrl;
// TODO: cleaner way to disallow deletion
if (!confirm)
return View ("RemovePost",e);
BlogManager.RemovePost (id);
BlogManager.RemovePost (postid);
if (string.IsNullOrWhiteSpace(returnUrl))
return RedirectToAction ("Index");
return Redirect (returnUrl);

@ -106,7 +106,7 @@ namespace Yavsc.Controllers
AuthToken gat = oa.GetToken (Request, (string)Session ["state"], out msg);
if (gat == null) {
YavscHelpers.Notice(ViewData, msg);
YavscHelpers.Notify(ViewData, msg);
return View ("Auth");
}
SaveToken (gat);
@ -143,7 +143,7 @@ namespace Yavsc.Controllers
OAuth2 oa = new OAuth2 (AuthGRU);
AuthToken gat = oa.GetToken (Request, (string)Session ["state"], out msg);
if (gat == null) {
YavscHelpers.Notice(ViewData, msg);
YavscHelpers.Notify(ViewData, msg);
return View ();
}
string returnUrl = (string)Session ["returnUrl"];

@ -121,7 +121,7 @@ namespace Yavsc.Controllers
using (System.Net.Mail.SmtpClient sc = new SmtpClient())
{
sc.Send (msg);
YavscHelpers.Notice(ViewData, LocalizedText.Message_sent);
YavscHelpers.Notify(ViewData, LocalizedText.Message_sent);
return View (new { email=email, reason="", body="" });
}
}

@ -47,17 +47,33 @@ namespace Yavsc
routes.IgnoreRoute ("favicon.png"); // favorite icon
routes.IgnoreRoute ("robots.txt"); // for search engine robots
routes.MapRoute (
"View",
"v/{title}",
"Titles",
"t/{title}",
new { controller = "Blogs", action = "Index",
title=UrlParameter.Optional }
);
routes.MapRoute (
"Blogs",
"b/{user}/{title}",
"b/{user}",
new { controller = "Blogs",
action = "UserPosts",
user="Paul Schneider" }
);
routes.MapRoute (
"BlogByTitle",
"by/{user}/{title}/{id}",
new { controller = "Blogs",
action = "UserPosts",
user="Paul Schneider",
title=UrlParameter.Optional,
id=UrlParameter.Optional }
);
routes.MapRoute (
"BlogById",
"b/{action}/{postid}",
new { controller = "Blogs", action = "Index",
user=UrlParameter.Optional,
title=UrlParameter.Optional }
postid=UrlParameter.Optional }
);
/* routes.MapRoute (
"Artistes",

@ -13,6 +13,7 @@ using System.Web.UI;
using System.Linq.Expressions;
using System.Web.Profile;
using System.Web.Script.Serialization;
using System.Web.Mvc;
namespace Yavsc.Helpers
{
@ -214,14 +215,22 @@ namespace Yavsc.Helpers
return serializer.Serialize(obj);
}
/// <summary>
/// Notice the specified ViewData with message.
/// Notifies
/// </summary>
/// <param name="ViewData">View data.</param>
/// <param name="message">Message.</param>
public static void Notice (System.Web.Mvc.ViewDataDictionary ViewData, string message) {
if (ViewData ["Notifications"] == null)
ViewData ["Notifications"] = new List<string> ();
(ViewData ["Notifications"] as List<string>).Add (message.Replace("\'","\\\'"));
public static void Notify (this HtmlHelper helper, string message) {
Notify (helper.ViewData, message);
}
/// <summary>
/// Notify the specified viewData and message.
/// </summary>
/// <param name="viewData">View data.</param>
/// <param name="message">Message.</param>
public static void Notify(ViewDataDictionary viewData, string message) {
if (viewData ["Notifications"] == null)
viewData ["Notifications"] = new List<string> ();
(viewData ["Notifications"] as List<string>).Add (message.Replace("\'","\\\'"));
}
/// <summary>
/// Files the list.
@ -279,6 +288,53 @@ namespace Yavsc.Helpers
return new System.Web.Mvc.MvcHtmlString (str.ToString ());
}
/// <summary>
/// Renders the page links.
/// </summary>
/// <returns>The page links.</returns>
/// <param name="helper">Helper.</param>
/// <param name="ResultCount">Result count.</param>
/// <param name="PageSize">Page size.</param>
/// <param name="PageIndex">Page index.</param>
public static IHtmlString RenderPageLinks (
this HtmlHelper helper,
int PageIndex, int PageSize, int ResultCount,
string args="?PageIndex={0}",
string pagesLabel="Pages: ", string singlePage="",
string none="néant"
)
{
StringWriter strwr = new StringWriter ();
HtmlTextWriter writer = new HtmlTextWriter(strwr);
if (ResultCount > 0 && ResultCount > PageSize ) {
int pageCount = ((ResultCount-1) / PageSize) + 1;
if ( pageCount > 1 ) {
writer.WriteEncodedText (pagesLabel);
for (int pi = (PageIndex < 5) ? 0 : PageIndex - 5; pi < pageCount && pi < PageIndex + 5; pi++) {
if (PageIndex == pi)
writer.RenderBeginTag ("b");
else {
writer.AddAttribute (HtmlTextWriterAttribute.Href,
string.Format (args, pi));
writer.RenderBeginTag ("a");
}
writer.Write (pi + 1);
writer.RenderEndTag ();
writer.Write ("&nbsp;");
}
}
else {
writer.Write (singlePage);
}
}
if (ResultCount == 0) {
writer.Write (none);
}
return new MvcHtmlString(strwr.ToString());
}
}
}

@ -19,8 +19,9 @@
<script type="text/javascript">
var apiBaseUrl = '<%=Url.Content(Yavsc.WebApiConfig.UrlPrefixRelative)%>';
</script>
<script src="<%=Url.Content("~/Scripts/yavsc.js")%>"></script>
<script src="<%=Url.Content("~/Scripts/yavsc.scrollnotif.js")%>"></script>
<script src="<%=Url.Content("~/Scripts/yavsc.js")%>">
</script>
<asp:ContentPlaceHolder id="head" runat="server">
</asp:ContentPlaceHolder>
</head>
@ -29,34 +30,38 @@ var apiBaseUrl = '<%=Url.Content(Yavsc.WebApiConfig.UrlPrefixRelative)%>';
<asp:ContentPlaceHolder ID="overHeaderOne" runat="server">
<h1><a href="<%= Url.Content("~/") %>">
<%=ViewState["orgtitle"]%></a>
<span> -
<a href="<%= Url.Content("~/") %>"><%= YavscHelpers.SiteName %></a>
</span></h1>
- <a href="<%= Url.Content("~/") %>"><%= YavscHelpers.SiteName %></a>
</h1>
</asp:ContentPlaceHolder>
<asp:ContentPlaceHolder ID="header" runat="server"></asp:ContentPlaceHolder>
<div id="notifications"></div>
<%if (ViewData ["Notifications"]!=null) { %>
<script>
$(document).ready(function(){
<%if (ViewData ["Notifications"]!=null) { %>
<% foreach (string notice in (IEnumerable<string>) ViewData ["Notifications"] ) { %>
Yavsc.notice('<%=notice%>');
<% } %>
<% } %>
$body = $("body");
$(document).on({
ajaxStart: function() { $body.addClass("loading"); },
ajaxStop: function() { $body.removeClass("loading"); }
});
});
</script>
<% } %>
</header>
<nav data-type="background" data-speed="2">
<% if (Membership.GetUser()==null) { %>
<a href="<%= Url.Content("~/Account/Login/?returnUrl=") + Url.Encode( Request.Url.PathAndQuery )%>" class="menuitem" >
<a href="<%= Url.RouteUrl("Default", new { controller = "Account", action = "Login", returnUrl=Request.Url.PathAndQuery}) %>" class="menuitem" accesskey = "C">
<i class="fa fa-sign-in">Connexion</i>
</a>
<% } else { %>
<a href="<%=Url.Content("~/b/"+HttpContext.Current.User.Identity.Name)%>" accesskey = "B" class="menuitem" >
<a href="<%=Url.RouteUrl("Blogs", new { user = HttpContext.Current.User.Identity.Name } )%>" accesskey = "B" class="menuitem" >
<img src="<%=Url.AvatarUrl(HttpContext.Current.User.Identity.Name)%>" alt="vos billets" class="iconsmall" />
<span class="hint">Vos billets</span>
</a>
<a href="<%= Url.Content("~/Account/Profile/" + HttpContext.Current.User.Identity.Name) %>" accesskey="L" class="menuitem">
<a href="<%= Url.RouteUrl("Default", new { controller = "Account", action = "Profile", id = HttpContext.Current.User.Identity.Name} ) %>" accesskey="P" class="menuitem">
<i class="fa fa-user"><%= HttpContext.Current.User.Identity.Name %>
<span class="hint"> &Eacute;dition de votre profile </span></i>
</a>
@ -65,7 +70,7 @@ Yavsc.notice('<%=notice%>');
<span class="hint">&Eacute;dition d'un nouveau billet </span></i>
</a>
<a href="<%= Url.Content( "~/Account/Logout/?returnUrl=")+Url.Encode(Request.Url.PathAndQuery)%>" accesskey = "P" class="menuitem">
<a href="<%= Url.RouteUrl("Default", new { controller = "Account", action = "Logout", returnUrl=Request.Url.PathAndQuery}) %>" accesskey = "C" class="menuitem">
<i class="fa fa-sign-out">Deconnexion</i></a>
<% } %>
</nav>
@ -93,6 +98,6 @@ Yavsc.notice('<%=notice%>');
<div id="gspacer" class="control"><div class="g-plusone" data-annotation="inline" data-width="170"></div>
</div>
</div>
</footer>
</footer><div class="modal"></div>
</body>
</html>

@ -0,0 +1,189 @@
// knockout-jqAutocomplete 0.4.3 | (c) 2015 Ryan Niemeyer | http://www.opensource.org/licenses/mit-license
;(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD anonymous module
define(["knockout", "jquery", "jquery-ui/autocomplete"], factory);
} else {
// No module loader - put directly in global namespace
factory(window.ko, jQuery);
}
})(function(ko, $) {
var JqAuto = function() {
var self = this,
unwrap = ko.utils.unwrapObservable; //support older KO versions that did not have ko.unwrap
//binding's init function
this.init = function(element, valueAccessor, allBindings, data, context) {
var existingSelect, existingChange,
options = unwrap(valueAccessor()),
config = {},
filter = typeof options.filter === "function" ? options.filter : self.defaultFilter;
//extend with global options
ko.utils.extend(config, self.options);
//override with options passed in binding
ko.utils.extend(config, options.options);
//get source from a function (can be remote call)
if (typeof options.source === "function" && !ko.isObservable(options.source)) {
config.source = function(request, response) {
//provide a wrapper to the normal response callback
var callback = function(data) {
self.processOptions(valueAccessor, null, data, request, response);
};
//call the provided function for retrieving data
options.source.call(context.$data, request.term, callback);
};
}
else {
//process local data
config.source = self.processOptions.bind(self, valueAccessor, filter, options.source);
}
//save any passed in select/change calls
existingSelect = typeof config.select === "function" && config.select;
existingChange = typeof config.change === "function" && config.change;
//handle updating the actual value
config.select = function(event, ui) {
if (ui.item && ui.item.actual) {
options.value(ui.item.actual);
if (ko.isWriteableObservable(options.dataValue)) {
options.dataValue(ui.item.data);
}
}
if (existingSelect) {
existingSelect.apply(this, arguments);
}
};
//user made a change without selecting a value from the list
config.change = function(event, ui) {
if (!ui.item || !ui.item.actual) {
options.value(event.target && event.target.value);
if (ko.isWriteableObservable(options.dataValue)) {
options.dataValue(null);
}
}
if (existingChange) {
existingChange.apply(this, arguments);
}
};
//initialize the widget
var widget = $(element).autocomplete(config).data("ui-autocomplete");
//render a template for the items
if (options.template) {
widget._renderItem = self.renderItem.bind(self, options.template, context);
}
//destroy the widget if KO removes the element
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
if (widget && typeof widget.destroy === "function") {
widget.destroy();
widget = null;
}
});
};
//the binding's update function. keep value in sync with model
this.update = function(element, valueAccessor) {
var propNames, sources,
options = unwrap(valueAccessor()),
value = unwrap(options && options.value);
if (!value && value !== 0) {
value = "";
}
// find the appropriate value for the input
sources = unwrap(options.source);
propNames = self.getPropertyNames(valueAccessor);
// if there is local data, then try to determine the appropriate value for the input
if ($.isArray(sources) && propNames.value) {
value = ko.utils.arrayFirst(sources, function (opt) {
return opt[propNames.value] == value;
}
) || value;
}
if (propNames.input && value && typeof value === "object") {
element.value = value[propNames.input];
}
else {
element.value = value;
}
};
//if dealing with local data, the default filtering function
this.defaultFilter = function(item, term) {
term = term && term.toLowerCase();
return (item || item === 0) && ko.toJSON(item).toLowerCase().indexOf(term) > -1;
};
//filter/map options to be in a format that autocomplete requires
this.processOptions = function(valueAccessor, filter, data, request, response) {
var item, index, length,
items = unwrap(data) || [],
results = [],
props = this.getPropertyNames(valueAccessor);
//filter/map items
for (index = 0, length = items.length; index < length; index++) {
item = items[index];
if (!filter || filter(item, request.term)) {
results.push({
label: props.label ? item[props.label] : item.toString(),
value: props.input ? item[props.input] : item.toString(),
actual: props.value ? item[props.value] : item,
data: item
});
}
}
//call autocomplete callback to display list
response(results);
};
//if specified, use a template to render an item
this.renderItem = function(templateName, context, ul, item) {
var $li = $("<li></li>").appendTo(ul),
itemContext = context.createChildContext(item.data);
//apply the template binding
ko.applyBindingsToNode($li[0], { template: templateName }, itemContext);
//clean up
$li.one("remove", ko.cleanNode.bind(ko, $li[0]));
return $li;
};
//retrieve the property names to use for the label, input, and value
this.getPropertyNames = function(valueAccessor) {
var options = ko.toJS(valueAccessor());
return {
label: options.labelProp || options.valueProp,
input: options.inputProp || options.labelProp || options.valueProp,
value: options.valueProp
};
};
//default global options passed into autocomplete widget
this.options = {
autoFocus: true,
delay: 50
};
};
ko.bindingHandlers.jqAuto = new JqAuto();
});

@ -0,0 +1,2 @@
// knockout-jqAutocomplete 0.4.3 | (c) 2015 Ryan Niemeyer | http://www.opensource.org/licenses/mit-license
!function(a){"function"==typeof define&&define.amd?define(["knockout","jquery","jquery-ui/autocomplete"],a):a(window.ko,jQuery)}(function(a,b){var c=function(){var c=this,d=a.utils.unwrapObservable;this.init=function(e,f,g,h,i){var j,k,l=d(f()),m={},n="function"==typeof l.filter?l.filter:c.defaultFilter;a.utils.extend(m,c.options),a.utils.extend(m,l.options),m.source="function"!=typeof l.source||a.isObservable(l.source)?c.processOptions.bind(c,f,n,l.source):function(a,b){var d=function(d){c.processOptions(f,null,d,a,b)};l.source.call(i.$data,a.term,d)},j="function"==typeof m.select&&m.select,k="function"==typeof m.change&&m.change,m.select=function(b,c){c.item&&c.item.actual&&(l.value(c.item.actual),a.isWriteableObservable(l.dataValue)&&l.dataValue(c.item.data)),j&&j.apply(this,arguments)},m.change=function(b,c){c.item&&c.item.actual||(l.value(b.target&&b.target.value),a.isWriteableObservable(l.dataValue)&&l.dataValue(null)),k&&k.apply(this,arguments)};var o=b(e).autocomplete(m).data("ui-autocomplete");l.template&&(o._renderItem=c.renderItem.bind(c,l.template,i)),a.utils.domNodeDisposal.addDisposeCallback(e,function(){o&&"function"==typeof o.destroy&&(o.destroy(),o=null)})},this.update=function(e,f){var g,h,i=d(f()),j=d(i&&i.value);j||0===j||(j=""),h=d(i.source),g=c.getPropertyNames(f),b.isArray(h)&&g.value&&(j=a.utils.arrayFirst(h,function(a){return a[g.value]==j})||j),e.value=g.input&&j&&"object"==typeof j?j[g.input]:j},this.defaultFilter=function(b,c){return c=c&&c.toLowerCase(),(b||0===b)&&a.toJSON(b).toLowerCase().indexOf(c)>-1},this.processOptions=function(a,b,c,e,f){var g,h,i,j=d(c)||[],k=[],l=this.getPropertyNames(a);for(h=0,i=j.length;i>h;h++)g=j[h],(!b||b(g,e.term))&&k.push({label:l.label?g[l.label]:g.toString(),value:l.input?g[l.input]:g.toString(),actual:l.value?g[l.value]:g,data:g});f(k)},this.renderItem=function(c,d,e,f){var g=b("<li></li>").appendTo(e),h=d.createChildContext(f.data);return a.applyBindingsToNode(g[0],{template:c},h),g.one("remove",a.cleanNode.bind(a,g[0])),g},this.getPropertyNames=function(b){var c=a.toJS(b());return{label:c.labelProp||c.valueProp,input:c.inputProp||c.labelProp||c.valueProp,value:c.valueProp}},this.options={autoFocus:!0,delay:50}};a.bindingHandlers.jqAuto=new c});

@ -1,6 +1,13 @@
var Yavsc = (function(apiBaseUrl){
var self = {};
function dumpprops(obj) {
var str = "";
for(var k in obj)
if (obj.hasOwnProperty(k))
str += k + " = " + obj[k] + "\n";
return (str); }
self.apiBaseUrl = (apiBaseUrl || '/api');
self.showHide = function () {
@ -33,8 +40,11 @@ self.notice = function (msg, msgok) {
self.onAjaxBadInput = function (data)
{
if (!data) { Yavsc.notice('no data'); return; }
if (!data.responseJSON) { Yavsc.notice('no json data:'+data); return; }
if (!Array.isArray(data.responseJSON)) { Yavsc.notice('Bad Input: '+data.responseJSON); return; }
$.each(data.responseJSON, function (key, value) {
var errspanid = "Err_cr_" + value.key.replace("model.","");
var errspanid = "Err_" + value.key;
var errspan = document.getElementById(errspanid);
if (errspan==null)
alert('enoent '+errspanid);
@ -47,9 +57,24 @@ self.notice = function (msg, msgok) {
self.onAjaxError = function (xhr, ajaxOptions, thrownError) {
if (xhr.status!=400)
Yavsc.notice(xhr.status+" : "+xhr.responseText);
else Yavsc.notice(false);
};
return self;
})();
$(document).ready(function(){
var $window = $(window);
$(window).scroll(function() {
var $ns = $('#notifications');
if ($ns.has('*').length>0) {
if ($window.scrollTop()>375) {
$ns.css('position','fixed');
$ns.css('z-index',2);
$ns.css('top',0);
}
else {
$ns.css('position','static');
$ns.css('z-index',1);
}}
});
});

@ -25,25 +25,19 @@
<hr>
<script>
function dumpprops(obj) {
var str = "";
for(var k in obj)
if (obj.hasOwnProperty(k))
str += k + " = " + obj[k] + "\n";
return (str); }
$(document).ready(function(){
$('#hidesource').click(function(){
$('#source').addClass('hidden');
$('#viewsource').removeClass('hidden');
$('#hidesource').addClass('hidden');
});
$('#viewsource').click(function(){
$('#source').removeClass('hidden');
$('#viewsource').addClass('hidden');
$('#hidesource').removeClass('hidden');
});
$('#hidesource').click(function(){
$('#source').addClass('hidden');
$('#viewsource').removeClass('hidden');
$('#hidesource').addClass('hidden');
});
$('#viewsource').click(function(){
$('#source').removeClass('hidden');
$('#viewsource').addClass('hidden');
$('#hidesource').removeClass('hidden');
});
jQuery('.placard').hallo({plugins: {'hallo-image-insert-edit': { lang: 'fr' } } });

@ -4,7 +4,7 @@
<div>
<% foreach (var g in Model.GroupByTitle()) { %>
<h2><%=Html.ActionLink(g.Key, "Title", "Blogs", new { id = g.Key } , new { @class="userref" } )%></h2>
<h2><a href="<%= Url.RouteUrl("Titles", new { title = g.Key }) %>" class="usertitleref"><%=Html.Encode(g.Key)%></a></h2>
<% foreach (var p in g) { %>
<div class="postpreview">
<p><%= Html.Markdown(p.Intro,"/bfiles/"+p.Id+"/") %></p>
@ -12,16 +12,5 @@
</div> <% } %>
<% } %>
</div>
<form runat="server" id="form1" method="GET">
<%
rp1.ResultCount = (int) ViewData["ResultCount"];
rp1.PageSize = (int) ViewData ["PageSize"];
rp1.PageIndex = (int) ViewData["PageIndex"];
rp1.None = Html.Translate("no content");
%>
<yavsc:ResultPages id="rp1" runat="server" >
<None>Aucun résultat</None>
</yavsc:ResultPages>
</form>
<%= Html.RenderPageLinks((int)ViewData["PageIndex"],(int)ViewData["PageSize"],(int)ViewData["ResultCount"])%>
</asp:Content>

@ -0,0 +1,8 @@
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%= (int) ViewData["ResultCount"] %>
rp1.PageSize = (int) ViewData ["PageSize"];
rp1.PageIndex = (int) ViewData["PageIndex"];
rp1.None = Html.Translate("no content");

@ -1,15 +1,15 @@
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<BasePost>" %>
<aside>
(<%= Model.Posted.ToString("yyyy/MM/dd") %>
- <%= Model.Modified.ToString("yyyy/MM/dd") %> <%= Model.Visible? "":", Invisible!" %>)
(<%= Model.Posted.ToString("D") %>
- <%= Model.Modified.ToString("D") %> <%= Model.Visible? "":", Invisible!" %>)
<% if (Membership.GetUser()!=null) {
if (Membership.GetUser().UserName==Model.Author || Roles.IsUserInRole("Admin"))
{ %>
<i class="fa fa-tag"><%=Html.Translate("DoTag")%></i>
<a href="<%= Url.RouteUrl("Default", new { action = "Edit", controller = "Blogs", id = Model.Id })%>" class="actionlink">
<% if (Model is BlogEntry) { %><%= Html.Partial("TagControl",Model)%><% } %>
<a href="<%= Url.RouteUrl("BlogById", new { action = "Edit", postid = Model.Id })%>" class="actionlink">
<i class="fa fa-pencil"><%=Html.Translate("Edit")%></i>
</a>
<a href="<%= Url.RouteUrl("Default", new { action = "RemovePost", controller = "Blogs", id = Model.Id })%>" class="actionlink">
<a href="<%= Url.RouteUrl("BlogById", new { action = "RemovePost", postid = Model.Id })%>" class="actionlink">
<i class="fa fa-remove"><%=Html.Translate("Remove")%></i></a>
<% }} %>
</aside>

@ -0,0 +1,97 @@
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<BlogEntry>" %>
<ul id="tags">
<% if (Model.Tags != null) foreach (string tagname in Model.Tags) { %>
<li><%= tagname %></li>
<% } %>
</ul>
<% if (Membership.GetUser()!=null) { %>
<% if (Membership.GetUser().UserName==Model.Author || Roles.IsUserInRole("Admin"))
{ // grant all permissions: to choose a given set of tags, also create some new tags %>
<span id="viewtagger">
<i class="fa fa-tag menuitem" id="viewtaggerbtn"><%=Html.Translate("DoTag")%></i></span>
<span id="hidetagger" class="hidden">
<i class="fa fa-tag menuitem" id="hidetaggerbtn" ><%=Html.Translate("Hide")%></i>
Note: Ils sont utilisé pour classifier le document. Par exemple, le tag <code>Accueil</code> rend le document
éligible à une place en page d'Accueil.
</span>
<form id="tagger" class="hidden">
<fieldset>
<legend>Associer des tags au billet</legend>
<label for="newtag"><%= Html.Translate("Tag_name")%>: </label>
<span id="Err_tag" class="error"></span>
<input type="text" id="newtag">
<span id="Err_model" class="error"></span>
<input id="sendnewtag" type="submit" class="fa fa-tag" value="<%=Html.Translate("Submit")%>">
</fieldset>
</form>
<script>
$(document).ready(function(){
$('#hidetaggerbtn').click(function(){
$('#tagger').addClass('hidden');
$('#viewtagger').removeClass('hidden');
$('#hidetagger').addClass('hidden');
});
$('#viewtaggerbtn').click(function(){
$('#tagger').removeClass('hidden');
$('#viewtagger').addClass('hidden');
$('#hidetagger').removeClass('hidden');
});
$('#newtag').autocomplete({
minLength: 0,
delay: 200,
source: function( request, response ) {
$.ajax({
url: "/api/Blogs/Tags",
type: "POST",
data: {
pattern: request.term
},
success: function( data ) {
response( data );
}
});
},
select: function( event, ui ) {
console.log( ui.item ?
"Selected: " + ui.item.label :
"Nothing selected, input was " + this.value);
},
open: function() {
$( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" );
},
close: function() {
$( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" );
}
});
$('#tagger').on('submit', function(e) { e.preventDefault(); });
$('#sendnewtag').click(function(){
var data = {
postid: <%= Model.Id %>,
tag: $('#newtag').val()
}
$.ajax({
url: '/api/Blogs/Tag/',
type: 'POST',
data: data,
success: function() {
$('<li>'+data.tag+'</li>').appendTo('#tags');
$('#newtag').val('');
},
statusCode: {
400: Yavsc.onAjaxBadInput
},
error: Yavsc.onAjaxError
});
});
});
</script>
<% } %>
<% } %>

@ -6,8 +6,8 @@
<asp:Content ContentPlaceHolderID="overHeaderOne" ID="header1" runat="server">
<h1 class="post">
<%=Html.ActionLink(Model.Title, "Title", new{id=Model.Title}, null)%>
- <a href="<%= Url.Content("~/") %>"><%= YavscHelpers.SiteName %></a>
<%=Html.ActionLink(Model.Title, "Title", new{title=Model.Title}, null)%>
- <a href="<%= Url.RouteUrl("Default") %>"><%= YavscHelpers.SiteName %></a>
</h1>
</asp:Content>

@ -30,7 +30,8 @@
<% string username = Membership.GetUser()==null ? null : Membership.GetUser().UserName; %>
<% foreach (var c in (Comment[]) BlogManager.GetComments(be.Id)) { %>
<div class="comment" style="min-height:32px;"> <img style="clear:left;float:left;max-width:32px;max-height:32px;margin:.3em;" src="<%= Url.Content("~/Account/Avatar/"+c.From) %>" alt="<%=c.From%>"/>
<div class="comment" style="min-height:32px;">
<img style="clear:left;float:left;max-width:32px;max-height:32px;margin:.3em;" src="<%= Url.RouteUrl("Blogs", new { user = c.From } ) %>" alt="<%=c.From%>"/>
<%= Html.Markdown(c.CommentText) %>
<% if (Model.Author == username || c.From == username ) { %>
<%= Html.ActionLink("Supprimer","RemoveComment", new { cmtid = c.Id } , new { @class="actionlink" })%>

@ -7,25 +7,26 @@
<asp:Content ContentPlaceHolderID="overHeaderOne" ID="header1" runat="server">
<% if (!string.IsNullOrEmpty((string)ViewData["Avatar"])) { %>
<a href="<%=Url.Content("~/Blog/"+Model.Author)%>" id="avatar">
<a href="<%=Url.RouteUrl( "Blogs", new { user = Model.Author } )%>" id="avatar">
<img src="<%=ViewData["Avatar"]%>" />
</a>
<% } %>
<h1 class="blogtitle">
<a href="<%=Url.Content("~/Blog/"+Model.Author)%>">
<a href="<%=Url.RouteUrl( "Blogs", new { user = Model.Author } )%>">
<%=Html.Encode(ViewData["BlogTitle"])%></a>
- <a href="<%= Url.Content("~/") %>"><%= YavscHelpers.SiteName %></a>
- <a href="<%= Url.RouteUrl( "Default") %>"><%= YavscHelpers.SiteName %></a>
</h1>
</asp:Content>
<asp:Content ContentPlaceHolderID="MainContent" ID="MainContentContent" runat="server">
<% foreach (BlogEntry e in this.Model) { %>
<div class="postpreview<% if (!e.Visible) { %> hiddenpost<% } %>" >
<h2><%= Html.ActionLink(e.Title,"UserPost", new { user=e.Author, title=e.Title, id = e.Id }, new { @class = "usertitleref" }) %></h2>
<h2><a href="<%= Url.RouteUrl("BlogByTitle", new { user=e.Author, title=e.Title, id = e.Id })%>" class="usertitleref">
<%=Html.Markdown(e.Title)%></a></h2>
<% bool truncated = false; %>
<%= Html.MarkdownToHtmlIntro(out truncated, e.Content,"/bfiles/"+e.Id+"/") %>
<% if (truncated) { %>
<a href="<%= Url.RouteUrl( "View", new { action="Title", title=e.Title}) %>">
<a href="<%= Url.RouteUrl( "BlogByTitle", new { user=e.Author , title=e.Title, id = e.Id}) %>">
<i>Html.Translate("ReadMore")</i></a>
<% } %>
<%= Html.Partial("PostActions",e)%>

@ -3,9 +3,6 @@
<asp:Content ContentPlaceHolderID="head" ID="head1" runat="server" >
<script type="text/javascript" src="<%=Url.Content("~/Scripts/stupidtable.js")%>"></script>
<script>
$(function(){
$("#tbwrts").stupidtable();
});
</script>
</asp:Content>
<asp:Content ContentPlaceHolderID="MainContent" ID="MainContentContent" runat="server">
@ -352,6 +349,9 @@ function addRow(){
$("#wr_Count").val(1);
$("#wr_UnitaryCost").val(0);
});
$("#tbwrts").stupidtable();
});
</script>

@ -142,7 +142,6 @@
<Folder Include="fonts\" />
<Folder Include="lib\" />
<Folder Include="App_Data\" />
<Folder Include="Test\" />
</ItemGroup>
<ItemGroup>
<Compile Include="Controllers\HomeController.cs" />
@ -190,7 +189,6 @@
<Compile Include="Formatters\EstimToPdfFormatter.MSAN.cs" />
<Compile Include="Helpers\TemplateException.cs" />
<Compile Include="Formatters\FormatterException.cs" />
<Compile Include="NUnitTestClass.cs" />
<Compile Include="TestExec.cs" />
<Compile Include="ApiControllers\WorkFlowController.cs" />
<Compile Include="ApiControllers\BasketController.cs" />
@ -432,7 +430,10 @@
<Content Include="Views\Blogs\Title.aspx" />
<Content Include="Views\Blogs\PostActions.ascx" />
<Content Include="Scripts\yavsc.tags.js" />
<Content Include="Scripts\yavsc.scrollnotif.js" />
<Content Include="Views\Blogs\TagControl.ascx" />
<Content Include="Scripts\knockout-jqAutocomplete.js" />
<Content Include="Scripts\knockout-jqAutocomplete.min.js" />
<Content Include="Views\Blogs\PageLinks.ascx" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />

@ -30,6 +30,8 @@ using System.ComponentModel.DataAnnotations;
namespace Yavsc.Model.Blogs
{
/// <summary>
/// Base post.
/// </summary>
@ -52,6 +54,9 @@ namespace Yavsc.Model.Blogs
id = value;
}
}
/// <summary>
/// The posted.
/// </summary>
@ -125,13 +130,21 @@ namespace Yavsc.Model.Blogs
}
}
/// <summary>
/// Gets or sets the photo.
/// </summary>
/// <value>The photo.</value>
public string Photo {
get;
set;
}
/// <summary>
/// Gets or sets a value indicating whether this <see cref="Yavsc.Model.Blogs.BlogEntry"/> is visible.
/// </summary>
/// <value><c>true</c> if visible; otherwise, <c>false</c>.</value>
public bool Visible { get; set ; }
}
}

@ -12,16 +12,20 @@ namespace Yavsc.Model.Blogs
/// </summary>
public class BlogEntry : BasePost {
/// <summary>
/// Gets or sets the photo.
/// Gets or sets the circles allowed to read this ticket.
/// An empty collection specifies a public post.
/// </summary>
/// <value>The photo.</value>
public string Photo {
get;
set;
}
/// <value>The circles.</value>
[Display(Name="Cercles autorisés")]
public long[] AllowedCircles { get; set; }
/// <summary>
/// Gets or sets the tags.
/// </summary>
/// <value>The tags.</value>
public string [] Tags { get; set ; }
string content;
@ -40,21 +44,6 @@ namespace Yavsc.Model.Blogs
}
}
/// <summary>
/// Gets or sets the circles allowed to read this ticket.
/// An empty collection specifies a public post.
/// </summary>
/// <value>The circles.</value>
[Display(Name="Cercles autorisés")]
public long[] AllowedCircles { get; set; }
/// <summary>
/// Gets or sets the tags.
/// </summary>
/// <value>The tags.</value>
public string [] Tags { get; set ; }
}
}

@ -122,7 +122,11 @@ namespace Yavsc.Model.Blogs
orderby be.Posted descending
group
new PostInfoByTitle { Author=be.Author, Id=be.Id,
Posted=be.Posted, Modified=be.Modified, Intro = MarkdownHelper.MarkdownIntro(be.Content, out truncated) }
Posted=be.Posted, Modified=be.Modified,
Intro = MarkdownHelper.MarkdownIntro(be.Content, out truncated),
Visible = be.Visible,
Photo = be.Photo
}
by be.Title
into titlegroup
select titlegroup;
@ -137,8 +141,15 @@ namespace Yavsc.Model.Blogs
return from be in this
orderby be.Posted descending
group
new PostInfoByUser { Title=be.Title, Id=be.Id,
Posted=be.Posted, Modified=be.Modified, Intro = MarkdownHelper.MarkdownIntro(be.Content, out truncated) }
new PostInfoByUser {
Title=be.Title,
Id=be.Id,
Posted=be.Posted,
Modified=be.Modified,
Intro = MarkdownHelper.MarkdownIntro(be.Content, out truncated) ,
Photo = be.Photo,
Visible = be.Visible
}
by be.Author
into usergroup
select usergroup;

@ -0,0 +1,45 @@
//
// PostTag.cs
//
// Author:
// Paul Schneider <paul@pschneider.fr>
//
// Copyright (c) 2015 GNU GPL
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Configuration;
using System.Collections.Generic;
using Yavsc.Model.Blogs;
using System.Linq;
using Yavsc.Model.Circles;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace Yavsc.Model.Blogs
{
public class PostTag {
public long PostId { get; set; }
[StringLength(512)]
[RegularExpression(@"^[a-zA-Z0-9 ]+$",ErrorMessage = "Un tag n'est composé que de lettres et de chiffres, les espaces" +
"sont autorisés")]
[Required(ErrorMessage = "S'il vous plait, saisissez nom de tag")]
public string Tag { get; set; }
}
}

@ -1,3 +1,16 @@
2015-10-17 Paul Schneider <paul@pschneider.fr>
* PostTag.cs:
* BasePost.cs:
* YavscModel.csproj:
* BlogEntry.cs:
* LocalizedText.resx:
* Automate.cs:
* LocalizedText.fr.resx:
* LocalizedText.Designer.cs:
* BlogEntryCollection.cs:
* LocalizedText.fr.Designer.cs:
2015-10-13 Paul Schneider <paul@pschneider.fr>
* BasePost.cs: refactoring:

@ -46,165 +46,177 @@ namespace Yavsc.Model {
}
}
public static string was_added_to_the_empty_role {
public static string EventWebPage {
get {
return ResourceManager.GetString("was_added_to_the_empty_role", resourceCulture);
return ResourceManager.GetString("EventWebPage", resourceCulture);
}
}
public static string Bill_edition {
public static string ProviderId {
get {
return ResourceManager.GetString("Bill_edition", resourceCulture);
return ResourceManager.GetString("ProviderId", resourceCulture);
}
}
public static string Tex_version {
public static string Pdf_version {
get {
return ResourceManager.GetString("Tex_version", resourceCulture);
return ResourceManager.GetString("Pdf_version", resourceCulture);
}
}
public static string Message_sent {
public static string Circles {
get {
return ResourceManager.GetString("Message_sent", resourceCulture);
return ResourceManager.GetString("Circles", resourceCulture);
}
}
public static string Count {
public static string DuplicateEmail {
get {
return ResourceManager.GetString("Count", resourceCulture);
return ResourceManager.GetString("DuplicateEmail", resourceCulture);
}
}
public static string Create {
public static string Preview {
get {
return ResourceManager.GetString("Create", resourceCulture);
return ResourceManager.GetString("Preview", resourceCulture);
}
}
public static string Description {
public static string DisplayName {
get {
return ResourceManager.GetString("Description", resourceCulture);
return ResourceManager.GetString("DisplayName", resourceCulture);
}
}
public static string Profile_edition {
public static string none {
get {
return ResourceManager.GetString("Profile_edition", resourceCulture);
return ResourceManager.GetString("none", resourceCulture);
}
}
public static string Title {
public static string ProviderName {
get {
return ResourceManager.GetString("Title", resourceCulture);
return ResourceManager.GetString("ProviderName", resourceCulture);
}
}
public static string My_Estimates {
public static string Not_Approuved {
get {
return ResourceManager.GetString("My_Estimates", resourceCulture);
return ResourceManager.GetString("Not_Approuved", resourceCulture);
}
}
public static string Google_error {
public static string User_name {
get {
return ResourceManager.GetString("Google_error", resourceCulture);
return ResourceManager.GetString("User_name", resourceCulture);
}
}
public static string StartDate {
public static string Estimate_not_found {
get {
return ResourceManager.GetString("StartDate", resourceCulture);
return ResourceManager.GetString("Estimate_not_found", resourceCulture);
}
}
public static string no_content {
public static string was_added_to_the_empty_role {
get {
return ResourceManager.GetString("no_content", resourceCulture);
return ResourceManager.GetString("was_added_to_the_empty_role", resourceCulture);
}
}
public static string DuplicateEmail {
public static string Members {
get {
return ResourceManager.GetString("DuplicateEmail", resourceCulture);
return ResourceManager.GetString("Members", resourceCulture);
}
}
public static string Ciffer {
public static string Google_calendar {
get {
return ResourceManager.GetString("Ciffer", resourceCulture);
return ResourceManager.GetString("Google_calendar", resourceCulture);
}
}
public static string Modify {
public static string Welcome {
get {
return ResourceManager.GetString("Modify", resourceCulture);
return ResourceManager.GetString("Welcome", resourceCulture);
}
}
public static string MaxDate {
public static string Private_circle {
get {
return ResourceManager.GetString("MaxDate", resourceCulture);
return ResourceManager.GetString("Private_circle", resourceCulture);
}
}
public static string younotadmin {
public static string ImportException {
get {
return ResourceManager.GetString("younotadmin", resourceCulture);
return ResourceManager.GetString("ImportException", resourceCulture);
}
}
public static string ProviderName {
public static string access_denied {
get {
return ResourceManager.GetString("ProviderName", resourceCulture);
return ResourceManager.GetString("access_denied", resourceCulture);
}
}
public static string Date_search {
public static string Ciffer {
get {
return ResourceManager.GetString("Date_search", resourceCulture);
return ResourceManager.GetString("Ciffer", resourceCulture);
}
}
public static string Members {
public static string Create {
get {
return ResourceManager.GetString("Members", resourceCulture);
return ResourceManager.GetString("Create", resourceCulture);
}
}
public static string ImportException {
public static string Submit {
get {
return ResourceManager.GetString("ImportException", resourceCulture);
return ResourceManager.GetString("Submit", resourceCulture);
}
}
public static string Preview {
public static string ImgLocator {
get {
return ResourceManager.GetString("Preview", resourceCulture);
return ResourceManager.GetString("ImgLocator", resourceCulture);
}
}
public static string Register {
public static string entries {
get {
return ResourceManager.GetString("Register", resourceCulture);
return ResourceManager.GetString("entries", resourceCulture);
}
}
public static string View_source {
public static string Description {
get {
return ResourceManager.GetString("View_source", resourceCulture);
return ResourceManager.GetString("Description", resourceCulture);
}
}
public static string Hide_source {
public static string Google_error {
get {
return ResourceManager.GetString("Hide_source", resourceCulture);
return ResourceManager.GetString("Google_error", resourceCulture);
}
}
public static string access_denied {
public static string Comment {
get {
return ResourceManager.GetString("access_denied", resourceCulture);
return ResourceManager.GetString("Comment", resourceCulture);
}
}
public static string Tex_version {
get {
return ResourceManager.GetString("Tex_version", resourceCulture);
}
}
public static string Item_added_to_basket {
get {
return ResourceManager.GetString("Item_added_to_basket", resourceCulture);
}
}
@ -220,207 +232,219 @@ namespace Yavsc.Model {
}
}
public static string EndDate {
public static string Hide {
get {
return ResourceManager.GetString("EndDate", resourceCulture);
return ResourceManager.GetString("Hide", resourceCulture);
}
}
public static string Google_calendar {
public static string Register {
get {
return ResourceManager.GetString("Google_calendar", resourceCulture);
return ResourceManager.GetString("Register", resourceCulture);
}
}
public static string Consultant {
public static string younotadmin {
get {
return ResourceManager.GetString("Consultant", resourceCulture);
return ResourceManager.GetString("younotadmin", resourceCulture);
}
}
public static string EventWebPage {
public static string Location {
get {
return ResourceManager.GetString("EventWebPage", resourceCulture);
return ResourceManager.GetString("Location", resourceCulture);
}
}
public static string ImgLocator {
public static string New_Tag {
get {
return ResourceManager.GetString("ImgLocator", resourceCulture);
return ResourceManager.GetString("New_Tag", resourceCulture);
}
}
public static string DoTag {
public static string Modify {
get {
return ResourceManager.GetString("DoTag", resourceCulture);
return ResourceManager.GetString("Modify", resourceCulture);
}
}
public static string Not_Approuved {
public static string Remove {
get {
return ResourceManager.GetString("Not_Approuved", resourceCulture);
return ResourceManager.GetString("Remove", resourceCulture);
}
}
public static string Private_circle {
public static string Title {
get {
return ResourceManager.GetString("Private_circle", resourceCulture);
return ResourceManager.GetString("Title", resourceCulture);
}
}
public static string DocTemplateException {
public static string Tag_name {
get {
return ResourceManager.GetString("DocTemplateException", resourceCulture);
return ResourceManager.GetString("Tag_name", resourceCulture);
}
}
public static string Unitary_cost {
public static string Message_sent {
get {
return ResourceManager.GetString("Unitary_cost", resourceCulture);
return ResourceManager.GetString("Message_sent", resourceCulture);
}
}
public static string Circles {
public static string Offline {
get {
return ResourceManager.GetString("Circles", resourceCulture);
return ResourceManager.GetString("Offline", resourceCulture);
}
}
public static string Location {
public static string Bill_edition {
get {
return ResourceManager.GetString("Location", resourceCulture);
return ResourceManager.GetString("Bill_edition", resourceCulture);
}
}
public static string Remember_me {
public static string InternalServerError {
get {
return ResourceManager.GetString("Remember_me", resourceCulture);
return ResourceManager.GetString("InternalServerError", resourceCulture);
}
}
public static string Remove {
public static string MaxDate {
get {
return ResourceManager.GetString("Remove", resourceCulture);
return ResourceManager.GetString("MaxDate", resourceCulture);
}
}
public static string none {
public static string Count {
get {
return ResourceManager.GetString("none", resourceCulture);
return ResourceManager.GetString("Count", resourceCulture);
}
}
public static string User_List {
public static string Edit {
get {
return ResourceManager.GetString("User_List", resourceCulture);
return ResourceManager.GetString("Edit", resourceCulture);
}
}
public static string Estimate_not_found {
public static string Date_search {
get {
return ResourceManager.GetString("Estimate_not_found", resourceCulture);
return ResourceManager.GetString("Date_search", resourceCulture);
}
}
public static string ProviderId {
public static string View_source {
get {
return ResourceManager.GetString("ProviderId", resourceCulture);
return ResourceManager.GetString("View_source", resourceCulture);
}
}
public static string Welcome {
public static string role_created {
get {
return ResourceManager.GetString("Welcome", resourceCulture);
return ResourceManager.GetString("role_created", resourceCulture);
}
}
public static string Online {
public static string ReadMore {
get {
return ResourceManager.GetString("Online", resourceCulture);
return ResourceManager.GetString("ReadMore", resourceCulture);
}
}
public static string Home {
public static string EndDate {
get {
return ResourceManager.GetString("Home", resourceCulture);
return ResourceManager.GetString("EndDate", resourceCulture);
}
}
public static string Offline {
public static string MinDate {
get {
return ResourceManager.GetString("Offline", resourceCulture);
return ResourceManager.GetString("MinDate", resourceCulture);
}
}
public static string MinDate {
public static string User_List {
get {
return ResourceManager.GetString("MinDate", resourceCulture);
return ResourceManager.GetString("User_List", resourceCulture);
}
}
public static string Comment {
public static string Remember_me {
get {
return ResourceManager.GetString("Comment", resourceCulture);
return ResourceManager.GetString("Remember_me", resourceCulture);
}
}
public static string User_name {
public static string Home {
get {
return ResourceManager.GetString("User_name", resourceCulture);
return ResourceManager.GetString("Home", resourceCulture);
}
}
public static string DisplayName {
public static string Consultant {
get {
return ResourceManager.GetString("DisplayName", resourceCulture);
return ResourceManager.GetString("Consultant", resourceCulture);
}
}
public static string Pdf_version {
public static string was_added_to_the_role {
get {
return ResourceManager.GetString("Pdf_version", resourceCulture);
return ResourceManager.GetString("was_added_to_the_role", resourceCulture);
}
}
public static string ReadMore {
public static string DoTag {
get {
return ResourceManager.GetString("ReadMore", resourceCulture);
return ResourceManager.GetString("DoTag", resourceCulture);
}
}
public static string Item_added_to_basket {
public static string DocTemplateException {
get {
return ResourceManager.GetString("Item_added_to_basket", resourceCulture);
return ResourceManager.GetString("DocTemplateException", resourceCulture);
}
}
public static string role_created {
public static string no_content {
get {
return ResourceManager.GetString("role_created", resourceCulture);
return ResourceManager.GetString("no_content", resourceCulture);
}
}
public static string Edit {
public static string Unitary_cost {
get {
return ResourceManager.GetString("Edit", resourceCulture);
return ResourceManager.GetString("Unitary_cost", resourceCulture);
}
}
public static string InternalServerError {
public static string Online {
get {
return ResourceManager.GetString("InternalServerError", resourceCulture);
return ResourceManager.GetString("Online", resourceCulture);
}
}
public static string entries {
public static string StartDate {
get {
return ResourceManager.GetString("entries", resourceCulture);
return ResourceManager.GetString("StartDate", resourceCulture);
}
}
public static string was_added_to_the_role {
public static string Hide_source {
get {
return ResourceManager.GetString("was_added_to_the_role", resourceCulture);
return ResourceManager.GetString("Hide_source", resourceCulture);
}
}
public static string Profile_edition {
get {
return ResourceManager.GetString("Profile_edition", resourceCulture);
}
}
public static string My_Estimates {
get {
return ResourceManager.GetString("My_Estimates", resourceCulture);
}
}
}

@ -148,9 +148,9 @@ namespace Yavsc.Model {
}
}
public static string younotadmin {
public static string New_Tag {
get {
return ResourceManager.GetString("younotadmin", resourceCulture);
return ResourceManager.GetString("New_Tag", resourceCulture);
}
}
@ -250,6 +250,12 @@ namespace Yavsc.Model {
}
}
public static string Submit {
get {
return ResourceManager.GetString("Submit", resourceCulture);
}
}
public static string Not_Approuved {
get {
return ResourceManager.GetString("Not Approuved", resourceCulture);
@ -286,6 +292,12 @@ namespace Yavsc.Model {
}
}
public static string Tag_name {
get {
return ResourceManager.GetString("Tag_name", resourceCulture);
}
}
public static string Remove {
get {
return ResourceManager.GetString("Remove", resourceCulture);
@ -298,6 +310,12 @@ namespace Yavsc.Model {
}
}
public static string Hide {
get {
return ResourceManager.GetString("Hide", resourceCulture);
}
}
public static string Estimate_not_found {
get {
return ResourceManager.GetString("Estimate_not_found", resourceCulture);
@ -370,6 +388,12 @@ namespace Yavsc.Model {
}
}
public static string younotadmin {
get {
return ResourceManager.GetString("younotadmin", resourceCulture);
}
}
public static string Item_added_to_basket {
get {
return ResourceManager.GetString("Item_added_to_basket", resourceCulture);

@ -35,6 +35,7 @@
<data name="Google_error"><value>Erreur Google : {0}</value></data>
<data name="Hide_source"><value>Cacher le texte source du billet</value></data>
<data name="Home"><value>Accueil</value></data>
<data name="Hide"><value>Cacher</value></data>
<data name="ImgLocator"><value>URI de l'image</value></data>
<data name="ImportException"><value>Exception à l'import</value></data>
<data name="InternalServerError"><value>Erreur serveur interne</value></data>
@ -46,6 +47,7 @@
<data name="MinDate"><value>Date minimale du rendez-vous</value></data>
<data name="Modify"><value>Modifier</value></data>
<data name="My_Estimates"><value>Mes estimations</value></data>
<data name="New_Tag"><value>Nouveau Tag</value></data>
<data name="none"><value>aucun(e)</value></data>
<data name="Not Approuved"><value>Non approuvé</value></data>
<data name="no_content"><value>pas de contenu</value></data>
@ -63,8 +65,10 @@
<data name="Remove"><value>Supprimer</value></data>
<data name="role_created"><value>Rôle créé</value></data>
<data name="StartDate"><value>Date de démarrage</value></data>
<data name="Submit"><value>Soumettre</value></data>
<data name="Tex_version"><value>Version LaTeX</value></data>
<data name="Title"><value>Titre</value></data>
<data name="Tag_name"><value>Nom du tag</value></data>
<data name="Unitary_cost"><value>Coût unitaire</value></data>
<data name="User List"><value>Liste des utilisateurs</value><comment></comment></data>
<data name="User_name"><value>Nom d'utilisateur</value></data>

@ -33,6 +33,7 @@
<data name="Estimate_not_found"><value>Estimate not found</value></data>
<data name="EventWebPage"><value>Event Web page</value></data>
<data name="Home"><value>Home</value></data>
<data name="Hide"><value>Hide</value></data>
<data name="Hide_source"><value>Hide the bill source text</value></data>
<data name="entries"><value>entries</value></data>
<data name="Google_calendar"><value>Google calendar</value></data>
@ -48,6 +49,7 @@
<data name="MinDate"><value>Minimal date for the rendez-vous</value></data>
<data name="Modify"><value>Modify</value></data>
<data name="My_Estimates"><value>My estimates</value></data>
<data name="New_Tag"><value>New Tag</value></data>
<data name="none"><value>none</value></data>
<data name="no_content"><value>no content</value></data>
<data name="Not_Approuved"><value>Not Approuved</value></data>
@ -66,8 +68,10 @@
<data name="Remove"><value>Remove</value></data>
<data name="role_created"><value>role created</value></data>
<data name="StartDate"><value>Start date</value></data>
<data name="Submit"><value>Submit</value></data>
<data name="Tex_version"><value>LaTeX version</value></data>
<data name="Title"><value>Title</value></data>
<data name="Tag_name"><value>Tag name</value></data>
<data name="Unitary_cost"><value>Unitary_cost</value></data>
<data name="User_List"><value>User List</value><comment></comment></data>
<data name="User_name"><value>User name</value></data>

@ -31,7 +31,7 @@ namespace Yavsc.Model.WorkFlow
/// <summary>
/// Initializes a new instance of the Automate class.
/// </summary>
public Automate ()
public Automate ()
{
}
private Dictionary<TState,Dictionary<TLetter,TState>> transitions =

@ -173,6 +173,7 @@
<Compile Include="Blogs\MarkdownHelper.cs" />
<Compile Include="Blogs\UTBlogEntryCollection.cs" />
<Compile Include="Blogs\BasePost.cs" />
<Compile Include="Blogs\PostTag.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>

Loading…