11 Commits

Author SHA1 Message Date
3f1bfc1c3c fixies the refact of blog spot index
All checks were successful
Dotnet build and test / log-the-inputs (push) Successful in 5s
Dotnet build and test / build (push) Successful in 1m58s
2025-06-29 19:53:56 +01:00
fdf75934e5 fixes backend accept 2025-06-29 19:53:19 +01:00
f603d87b33 db update 2025-06-29 18:55:52 +01:00
bebca989d0 refact
All checks were successful
Dotnet build and test / log-the-inputs (push) Successful in 4s
Dotnet build and test / build (push) Successful in 2m30s
2025-06-29 18:44:35 +01:00
531797d348 refact
All checks were successful
Dotnet build and test / log-the-inputs (push) Successful in 4s
Dotnet build and test / build (push) Successful in 1m50s
2025-06-29 16:20:37 +01:00
2002b8b232 refactoring
All checks were successful
Dotnet build and test / log-the-inputs (push) Successful in 7s
Dotnet build and test / build (push) Successful in 1m48s
2025-06-29 16:12:16 +01:00
0e0a79c6cd a web resource authorisation 2025-06-29 11:53:25 +01:00
0f52a875de Migrate the db at startup 2025-06-29 11:52:57 +01:00
70771e5ab5 Implémentation de la publication d'un billet
All checks were successful
Dotnet build and test / log-the-inputs (push) Successful in 10s
Dotnet build and test / build (push) Successful in 2m0s
2025-06-28 16:14:52 +01:00
447d926ca6 Brusher Profile and Blog delete permisssion 2025-06-28 14:54:44 +01:00
b4870a1814 migration net9.0
All checks were successful
Dotnet build and test / log-the-inputs (push) Successful in 6s
Dotnet build and test / build (push) Successful in 1m47s
2025-06-16 02:30:32 +01:00
47 changed files with 23909 additions and 1828 deletions

View File

@ -44,7 +44,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build

View File

@ -1,7 +0,0 @@
on: workflow_call
jobs:
my_first_job:
runs-on: ubuntu-latest
steps:
- name: Run my action
uses: ./.github/worklflows/dotnet

View File

@ -15,14 +15,13 @@ WorkingDirectory=/srv/www/yavsc/
ExecStart=/srv/www/yavsc/Yavsc
Restart=always
Environment="HOME=/srv/www/yavsc"
Environment="ASPNETCORE_ENVIRONMENT=lua"
Environment="ASPNETCORE_ConnectionStrings__DefaultConnection=Server=localhost;Port=5432;Database=lua;Username=lua;Password=f3s-*Vx$;"
Environment="ASPNETCORE_ENVIRONMENT=Production"
Environment="ASPNETCORE_ConnectionStrings__DefaultConnection=YOUR Postgresql CONNECTION STRING"
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=isnd
SyslogIdentifier=yavsc
[Install]
WantedBy=multi-user.target

View File

@ -40,7 +40,7 @@ namespace Yavsc.ApiControllers
return Ok();
}
[HttpPost("query/reject")]
[HttpPost("query/accept")]
public IActionResult AcceptQuery(string billingCode, long queryId)
{
if (billingCode == null) return BadRequest("billingCode");
@ -51,7 +51,6 @@ namespace Yavsc.ApiControllers
billing.Decided = true;
dbContext.SaveChanges();
return Ok();
}
}
}

View File

@ -1,16 +1,19 @@

using Yavsc.Abstract.Identity;
namespace Yavsc
{
public interface IBlogPostPayLoad
{
string Content { get; set; }
string Photo { get; set; }
string? Content { get; set; }
string? Photo { get; set; }
}
public interface IBlogPost :IBlogPostPayLoad, ITrackedEntity, IIdentified<long>, ITitle
public interface IBlogPost : IBlogPostPayLoad, ITrackedEntity, IIdentified<long>, ITitle
{
string AuthorId { get; set; }
IApplicationUser Author { get; }
}
}

View File

@ -54,7 +54,7 @@ namespace Yavsc.Models.Google.Messaging
/// <summary>
/// The error.
/// </summary>
public string error;
public string? error;
}
/// <summary>

View File

@ -3,10 +3,10 @@
public interface IApplicationUser
{
string Id { get; set; }
string UserName { get; set; }
string Avatar { get ; set; }
IAccountBalance AccountBalance { get; set; }
string DedicatedGoogleCalendar { get; set; }
ILocation PostalAddress { get; set; }
string? UserName { get; set; }
string? Avatar { get ; set; }
IAccountBalance? AccountBalance { get; }
string? DedicatedGoogleCalendar { get; }
ILocation? PostalAddress { get; }
}
}

View File

@ -3,7 +3,7 @@ namespace Yavsc.Abstract.Identity.Security
public interface ICircleAuthorized
{
long Id { get; set; }
string OwnerId { get; }
string AuthorId { get; }
bool AuthorizeCircle(long circleId);
ICircleAuthorization [] GetACL();

View File

@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "9.0.6",
"commands": [
"dotnet-ef"
],
"rollForward": false
}
}
}

View File

@ -0,0 +1,17 @@
namespace Yavsc.Server.Exceptions;
[Serializable]
public class AuthorizationFailureException : Exception
{
public AuthorizationFailureException(Microsoft.AspNetCore.Authorization.AuthorizationResult auth) : base(auth?.Failure?.ToString()??auth?.ToString()??"AuthorizationResult failure")
{
}
public AuthorizationFailureException(string? message) : base(message)
{
}
public AuthorizationFailureException(string? message, Exception? innerException) : base(message, innerException)
{
}
}

View File

@ -24,13 +24,14 @@ namespace Yavsc.Helpers
return user.Identity.IsAuthenticated;
}
public static IEnumerable<BlogPost> UserPosts(this ApplicationDbContext dbContext, string posterId, string readerId)
public static IEnumerable<BlogPost> UserPosts(this ApplicationDbContext dbContext, string posterId, string? readerId)
{
if (readerId == null)
{
var userPosts = dbContext.BlogSpot.Include(
b => b.Author
).Where(x => ((x.AuthorId == posterId))).ToArray();
var userPosts = dbContext.blogSpotPublications.Include(
b => b.BlogPost
).Where(x => x.BlogPost.AuthorId == posterId)
.Select(x=>x.BlogPost).ToArray();
return userPosts;
}
else

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,108 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Yavsc.Migrations
{
/// <inheritdoc />
public partial class ActivityNulls : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "UserModified",
table: "Activities",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");
migrationBuilder.AlterColumn<string>(
name: "UserCreated",
table: "Activities",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");
migrationBuilder.AlterColumn<string>(
name: "SettingsClassName",
table: "Activities",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");
migrationBuilder.AlterColumn<string>(
name: "Photo",
table: "Activities",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");
migrationBuilder.AlterColumn<string>(
name: "ModeratorGroupName",
table: "Activities",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "UserModified",
table: "Activities",
type: "text",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "UserCreated",
table: "Activities",
type: "text",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "SettingsClassName",
table: "Activities",
type: "text",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Photo",
table: "Activities",
type: "text",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ModeratorGroupName",
table: "Activities",
type: "text",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,59 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Yavsc.Migrations
{
/// <inheritdoc />
public partial class BrusherProfileSchedulerId : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_BrusherProfile_Schedule_ScheduleOwnerId",
table: "BrusherProfile");
migrationBuilder.AlterColumn<string>(
name: "ScheduleOwnerId",
table: "BrusherProfile",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");
migrationBuilder.AddForeignKey(
name: "FK_BrusherProfile_Schedule_ScheduleOwnerId",
table: "BrusherProfile",
column: "ScheduleOwnerId",
principalTable: "Schedule",
principalColumn: "OwnerId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_BrusherProfile_Schedule_ScheduleOwnerId",
table: "BrusherProfile");
migrationBuilder.AlterColumn<string>(
name: "ScheduleOwnerId",
table: "BrusherProfile",
type: "text",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AddForeignKey(
name: "FK_BrusherProfile_Schedule_ScheduleOwnerId",
table: "BrusherProfile",
column: "ScheduleOwnerId",
principalTable: "Schedule",
principalColumn: "OwnerId",
onDelete: ReferentialAction.Cascade);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,38 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Yavsc.Migrations
{
/// <inheritdoc />
public partial class blogPostPub : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "blogspotPublications",
columns: table => new
{
BlogpostId = table.Column<long>(type: "bigint", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_blogspotPublications", x => x.BlogpostId);
table.ForeignKey(
name: "FK_blogspotPublications_BlogSpot_BlogpostId",
column: x => x.BlogpostId,
principalTable: "BlogSpot",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "blogspotPublications");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Yavsc.Migrations
{
/// <inheritdoc />
public partial class blogPusb2 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_blogspotPublications_BlogSpot_BlogpostId",
table: "blogspotPublications");
migrationBuilder.DropPrimaryKey(
name: "PK_blogspotPublications",
table: "blogspotPublications");
migrationBuilder.RenameTable(
name: "blogspotPublications",
newName: "blogSpotPublications");
migrationBuilder.AddColumn<bool>(
name: "Publish",
table: "BlogSpot",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddPrimaryKey(
name: "PK_blogSpotPublications",
table: "blogSpotPublications",
column: "BlogpostId");
migrationBuilder.AddForeignKey(
name: "FK_blogSpotPublications_BlogSpot_BlogpostId",
table: "blogSpotPublications",
column: "BlogpostId",
principalTable: "BlogSpot",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_blogSpotPublications_BlogSpot_BlogpostId",
table: "blogSpotPublications");
migrationBuilder.DropPrimaryKey(
name: "PK_blogSpotPublications",
table: "blogSpotPublications");
migrationBuilder.DropColumn(
name: "Publish",
table: "BlogSpot");
migrationBuilder.RenameTable(
name: "blogSpotPublications",
newName: "blogspotPublications");
migrationBuilder.AddPrimaryKey(
name: "PK_blogspotPublications",
table: "blogspotPublications",
column: "BlogpostId");
migrationBuilder.AddForeignKey(
name: "FK_blogspotPublications_BlogSpot_BlogpostId",
table: "blogspotPublications",
column: "BlogpostId",
principalTable: "BlogSpot",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Yavsc.Migrations
{
/// <inheritdoc />
public partial class blogPub2 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

View File

@ -774,6 +774,9 @@ namespace Yavsc.Migrations
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<bool>("Publish")
.HasColumnType("boolean");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(1024)
@ -857,6 +860,16 @@ namespace Yavsc.Migrations
b.ToTable("Comment");
});
modelBuilder.Entity("Yavsc.Models.BlogSpotPublication", b =>
{
b.Property<long>("BlogpostId")
.HasColumnType("bigint");
b.HasKey("BlogpostId");
b.ToTable("blogSpotPublications");
});
modelBuilder.Entity("Yavsc.Models.Calendar.Schedule", b =>
{
b.Property<string>("OwnerId")
@ -1123,7 +1136,6 @@ namespace Yavsc.Migrations
.HasColumnType("numeric");
b.Property<string>("ScheduleOwnerId")
.IsRequired()
.HasColumnType("text");
b.Property<decimal>("ShampooPrice")
@ -2081,7 +2093,6 @@ namespace Yavsc.Migrations
.HasColumnType("boolean");
b.Property<string>("ModeratorGroupName")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
@ -2092,22 +2103,18 @@ namespace Yavsc.Migrations
.HasColumnType("text");
b.Property<string>("Photo")
.IsRequired()
.HasColumnType("text");
b.Property<int>("Rate")
.HasColumnType("integer");
b.Property<string>("SettingsClassName")
.IsRequired()
.HasColumnType("text");
b.Property<string>("UserCreated")
.IsRequired()
.HasColumnType("text");
b.Property<string>("UserModified")
.IsRequired()
.HasColumnType("text");
b.HasKey("Code");
@ -2769,6 +2776,17 @@ namespace Yavsc.Migrations
b.Navigation("Post");
});
modelBuilder.Entity("Yavsc.Models.BlogSpotPublication", b =>
{
b.HasOne("Yavsc.Models.Blog.BlogPost", "BlogPost")
.WithMany()
.HasForeignKey("BlogpostId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("BlogPost");
});
modelBuilder.Entity("Yavsc.Models.Calendar.Schedule", b =>
{
b.HasOne("Yavsc.Models.ApplicationUser", "Owner")
@ -2840,9 +2858,7 @@ namespace Yavsc.Migrations
{
b.HasOne("Yavsc.Models.Calendar.Schedule", "Schedule")
.WithMany()
.HasForeignKey("ScheduleOwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
.HasForeignKey("ScheduleOwnerId");
b.HasOne("Yavsc.Models.Workflow.PerformerProfile", "BaseProfile")
.WithMany()

View File

@ -1,8 +1,4 @@

using System;
using System.Linq;
using System.Threading.Tasks;
using System.Threading;
using Yavsc.Models.Haircut;
using Yavsc.Models.IT.Evolution;
using Yavsc.Models.IT.Fixing;
@ -10,7 +6,6 @@ using Yavsc.Server.Models.EMailing;
using Yavsc.Server.Models.IT.SourceCode;
using Yavsc.Server.Models.IT;
using Yavsc.Models.Streaming;
using Yavsc.Models.Musical;
namespace Yavsc.Models
{
@ -32,7 +27,6 @@ namespace Yavsc.Models
using Attributes;
using Bank;
using Payment;
using Calendar;
using Blog;
using Yavsc.Abstract.Identity;
using Microsoft.EntityFrameworkCore;
@ -41,6 +35,7 @@ namespace Yavsc.Models
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Yavsc.Abstract.Models.Messaging;
using Org.BouncyCastle.Asn1.Crmf;
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
@ -51,7 +46,7 @@ namespace Yavsc.Models
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
@ -61,7 +56,7 @@ namespace Yavsc.Models
builder.Entity<Contact>().HasKey(x => new { x.OwnerId, x.UserId });
builder.Entity<DeviceDeclaration>().Property(x => x.DeclarationDate).HasDefaultValueSql("LOCALTIMESTAMP");
builder.Entity<BlogTag>().HasKey(x => new { x.PostId, x.TagId });
builder.Entity<ApplicationUser>().Property(u => u.FullName).IsRequired(false);
builder.Entity<ApplicationUser>().Property(u => u.DedicatedGoogleCalendar).IsRequired(false);
builder.Entity<ApplicationUser>().HasMany<ChatConnection>(c => c.Connections);
@ -81,7 +76,7 @@ namespace Yavsc.Models
builder.Entity<Models.Cratie.Option>().HasKey(o => new { o.Code, o.CodeScrutin });
builder.Entity<Notification>().Property(n => n.icon).HasDefaultValue("exclam");
builder.Entity<ChatRoomAccess>().HasKey(p => new { room = p.ChannelName, user = p.UserId });
builder.Entity<InstrumentRating>().HasAlternateKey(i => new { Instrument= i.InstrumentId, owner = i.OwnerId });
builder.Entity<InstrumentRating>().HasAlternateKey(i => new { Instrument = i.InstrumentId, owner = i.OwnerId });
foreach (var et in builder.Model.GetEntityTypes())
{
@ -89,23 +84,23 @@ namespace Yavsc.Models
et.FindProperty("DateCreated").SetAfterSaveBehavior(Microsoft.EntityFrameworkCore.Metadata.PropertySaveBehavior.Ignore);
}
builder.Entity<Activity>().Property(a=>a.ParentCode).IsRequired(false);
builder.Entity<Activity>().Property(a => a.ParentCode).IsRequired(false);
//builder.Entity<BlogPost>().HasOne(p => p.Author).WithMany(a => a.Posts);
}
// this is not a failback procedure.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var appSetup = (string) AppDomain.CurrentDomain.GetData(Constants.YavscConnectionStringEnvName);
if (!string.IsNullOrWhiteSpace(appSetup))
var appSetup = (string)AppDomain.CurrentDomain.GetData(Constants.YavscConnectionStringEnvName);
if (!string.IsNullOrWhiteSpace(appSetup))
{
optionsBuilder.UseNpgsql(appSetup);
return;
}
var envSetup = Environment.GetEnvironmentVariable(Constants.YavscConnectionStringEnvName);
if (envSetup!=null)
if (envSetup != null)
optionsBuilder.UseNpgsql(envSetup);
else optionsBuilder.UseNpgsql();
}
@ -125,7 +120,7 @@ namespace Yavsc.Models
/// Users posts
/// </summary>
/// <returns></returns>
public DbSet<Blog.BlogPost> BlogSpot { get; set; }
public DbSet<BlogPost> BlogSpot { get; set; }
/// <summary>
/// Skills powered by this site
@ -226,14 +221,14 @@ namespace Yavsc.Models
((ITrackedEntity)entity.Entity).UserModified = userId;
}
}
public int SaveChanges(string userId)
{
AddTimestamps(userId);
return base.SaveChanges();
}
public async Task<int> SaveChangesAsync(string userId, CancellationToken ctoken = default(CancellationToken))
{
@ -282,7 +277,7 @@ namespace Yavsc.Models
public DbSet<Comment> Comment { get; set; }
public DbSet<Announce> Announce { get; set; }
// TODO remove and opt for for memory only storing,
// as long as it must be set empty each time the service is restarted,
// and that chatting should be kept as must as possible independent from db context
@ -295,7 +290,7 @@ namespace Yavsc.Models
public DbSet<GitRepositoryReference> GitRepositoryReference { get; set; }
public DbSet<Project> Project { get; set; }
[Obsolete("use signaled flows")]
public DbSet<LiveFlow> LiveFlow { get; set; }
@ -304,6 +299,8 @@ namespace Yavsc.Models
public DbSet<InstrumentRating> InstrumentRating { get; set; }
public DbSet<Scope> Scopes { get; set; }
public DbSet<BlogSpotPublication> blogSpotPublications{ get; set; }
}
}

View File

@ -7,10 +7,12 @@ using Yavsc.Models.Identity;
using Yavsc.Models.Chat;
using Yavsc.Models.Bank;
using Yavsc.Models.Access;
using Yavsc.Abstract.Identity;
namespace Yavsc.Models
{
[Table("AspNetUsers")]
public class ApplicationUser : IdentityUser
public class ApplicationUser : IdentityUser, IApplicationUser
{
/// <summary>
/// Another me, as a byte array.TG7@Eu%80rufzkhbb
@ -22,10 +24,10 @@ namespace Yavsc.Models
/// </summary>
/// <returns></returns>
[MaxLength(512)]
public string Avatar { get; set; }
public string? Avatar { get; set; }
[MaxLength(512)]
public string FullName { get; set; }
public string? FullName { get; set; }
/// <summary>
@ -33,7 +35,7 @@ namespace Yavsc.Models
/// </summary>
/// <returns></returns>
[Display(Name = "Account balance")]
public virtual AccountBalance AccountBalance { get; set; }
public virtual AccountBalance? AccountBalance { get; set; }
/// <summary>
/// User's posts
@ -113,5 +115,8 @@ namespace Yavsc.Models
[InverseProperty("Member")]
public virtual List<CircleMember> Membership { get; set; }
IAccountBalance? IApplicationUser.AccountBalance => AccountBalance;
ILocation? IApplicationUser.PostalAddress { get => PostalAddress; }
}
}

View File

@ -5,6 +5,8 @@ using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Yavsc;
using Yavsc.Abstract.Identity;
using Yavsc.Abstract.Identity.Security;
using Yavsc.Attributes.Validation;
using Yavsc.Interfaces;
@ -14,7 +16,8 @@ using Yavsc.ViewModels.Blog;
namespace Yavsc.Models.Blog
{
public class BlogPost : BlogPostInputViewModel, IBlogPost, ICircleAuthorized, ITaggable<long>, IIdentified<long>
public class BlogPost : BlogPostBase,
IBlogPost, ICircleAuthorized, ITaggable<long>
{
[Key(), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Display(Name="Identifiant du post")]
@ -85,7 +88,6 @@ namespace Yavsc.Models.Blog
[InverseProperty("Post")]
public virtual List<Comment> Comments { get; set; }
[NotMapped]
public string OwnerId => AuthorId;
IApplicationUser IBlogPost.Author { get => this.Author; }
}
}

View File

@ -0,0 +1,15 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Yavsc.Models.Blog;
namespace Yavsc.Models
{
public class BlogSpotPublication
{
[Key]
public long BlogpostId { get; set; }
[ForeignKey("BlogpostId")]
public virtual BlogPost BlogPost{ get; set; }
}
}

View File

@ -60,7 +60,7 @@ namespace Yavsc.Models.Haircut
[DisplayFormat(ConvertEmptyStringToNull = true, NullDisplayText = "[Pas d'emploi du temps spécifié]")]
[Display(Name="Emploi du temps")]
public virtual Schedule Schedule { get; set; }
public virtual Schedule? Schedule { get; set; }
[Display(Name="Coupe femme cheveux longs"),DisplayFormat(DataFormatString="{0:C}")]

View File

@ -28,7 +28,7 @@ namespace Yavsc.Models.Workflow
[YaStringLength(512)]
[Display(Name = "Code du parent")]
[ForeignKey("Parent")]
public string ParentCode { get; set; }
public string? ParentCode { get; set; }
[Display(Name = "Activité parent"), JsonIgnore]
public virtual Activity Parent { get; set; }
@ -41,7 +41,7 @@ namespace Yavsc.Models.Workflow
public string Description { get; set; }
[Display(Name = "Photo")]
public string Photo { get; set; }
public string? Photo { get; set; }
[InverseProperty("Context")]
[DisplayAttribute(Name = "Services liés")]
@ -52,7 +52,7 @@ namespace Yavsc.Models.Workflow
/// </summary>
/// <returns></returns>
[DisplayAttribute(Name = "Groupe de modération")]
public string ModeratorGroupName { get; set; }
public string? ModeratorGroupName { get; set; }
/// <summary>
/// indice de recherche de cette activité
@ -64,7 +64,7 @@ namespace Yavsc.Models.Workflow
[DisplayFormatAttribute(DataFormatString="{0}%")]
public int Rate { get; set; }
[DisplayAttribute(Name = "Classe de paramétrage")]
public string SettingsClassName { get; set; }
public string? SettingsClassName { get; set; }
[InverseProperty("Context")]
[Display(Name="Formulaires de commande")]
@ -77,7 +77,7 @@ namespace Yavsc.Models.Workflow
}
[Display(Name="Createur")]
public string UserCreated
public string? UserCreated
{
get; set;
}
@ -89,7 +89,7 @@ namespace Yavsc.Models.Workflow
}
[Display(Name="Utilisateur ayant modifié le dernier")]
public string UserModified
public string? UserModified
{
get; set;
}

View File

@ -8,10 +8,10 @@ namespace Yavsc.Models.societe.com
public class CompanyInfoMessage
{
public bool success { get; set; }
public string errorType { get; set; }
public string errorCode { get; set; }
public string errorMessage { get; set; }
public CompanyInfo result { get; set; }
public string? errorType { get; set; }
public string? errorCode { get; set; }
public string? errorMessage { get; set; }
public CompanyInfo? result { get; set; }
}

View File

@ -0,0 +1,185 @@
using System.Diagnostics;
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using Yavsc;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Blog;
using Yavsc.Server.Exceptions;
using Yavsc.ViewModels.Auth;
using Yavsc.ViewModels.Blog;
public class BlogSpotService
{
private readonly ApplicationDbContext _context;
private readonly IAuthorizationService _authorizationService;
public BlogSpotService(ApplicationDbContext context,
IAuthorizationService authorizationService)
{
_authorizationService = authorizationService;
_context = context;
}
public BlogPost Create(string userId, BlogPostBase blogInput)
{
BlogPost post = new BlogPost
{
Title = blogInput.Title,
Content = blogInput.Content,
Photo = blogInput.Photo,
AuthorId = userId
};
_context.BlogSpot.Add(post);
_context.SaveChanges(userId);
return post;
}
public async Task<BlogPost> GetPostForEdition(ClaimsPrincipal user, long blogPostId)
{
var blog = await _context.BlogSpot.Include(x => x.Author).Include(x => x.ACL).SingleAsync(m => m.Id == blogPostId);
var auth = await _authorizationService.AuthorizeAsync(user, blog, new EditPermission());
if (!auth.Succeeded)
{
throw new AuthorizationFailureException(auth);
}
return blog;
}
public async Task<BlogPost> Details(ClaimsPrincipal user, long blogPostId)
{
BlogPost blog = await _context.BlogSpot
.Include(p => p.Author)
.Include(p => p.Tags)
.Include(p => p.Comments)
.Include(p => p.ACL)
.SingleAsync(m => m.Id == blogPostId);
if (blog == null)
{
return null;
}
var auth = await _authorizationService.AuthorizeAsync(user, blog, new ReadPermission());
if (!auth.Succeeded)
{
throw new AuthorizationFailureException(auth);
}
foreach (var c in blog.Comments)
{
c.Author = _context.Users.First(u => u.Id == c.AuthorId);
}
return blog;
}
public async Task Modify(ClaimsPrincipal user, BlogPostEditViewModel blogEdit)
{
var blog = _context.BlogSpot.SingleOrDefault(b => b.Id == blogEdit.Id);
Debug.Assert(blog != null);
var auth = await _authorizationService.AuthorizeAsync(user, blog, new EditPermission());
if (!auth.Succeeded)
{
throw new AuthorizationFailureException(auth);
}
blog.Content = blogEdit.Content;
blog.Title = blogEdit.Title;
blog.Photo = blogEdit.Photo;
blog.ACL = blogEdit.ACL;
// saves the change
_context.Update(blog);
var publication = await _context.blogSpotPublications.SingleOrDefaultAsync
(p=>p.BlogpostId==blogEdit.Id);
if (publication != null)
{
if (!blogEdit.Publish)
{
_context.blogSpotPublications.Remove(publication);
}
}
else
{
if (blogEdit.Publish)
{
_context.blogSpotPublications.Add(
new BlogSpotPublication
{
BlogpostId = blogEdit.Id
}
);
}
}
_context.SaveChanges(user.GetUserId());
}
public async Task<IEnumerable<IGrouping<string, IBlogPost>>> IndexByTitle(ClaimsPrincipal user, string id, int skip = 0, int take = 25)
{
IEnumerable<IBlogPost> posts;
if (user.Identity.IsAuthenticated)
{
string viewerId = user.GetUserId();
long[] userCircles = await _context.Circle.Include(c => c.Members).
Where(c => c.Members.Any(m => m.MemberId == viewerId))
.Select(c => c.Id).ToArrayAsync();
posts = _context.BlogSpot
.Include(b => b.Author)
.Include(p => p.ACL)
.Include(p => p.Tags)
.Include(p => p.Comments)
.Where(p => p.ACL == null
|| p.ACL.Count == 0
|| (p.AuthorId == viewerId)
|| (userCircles != null &&
p.ACL.Any(a => userCircles.Contains(a.CircleId)))
);
}
else
{
posts = _context.blogSpotPublications
.Include(p => p.BlogPost)
.Include(b => b.BlogPost.Author)
.Include(p => p.BlogPost.ACL)
.Include(p => p.BlogPost.Tags)
.Include(p => p.BlogPost.Comments)
.Where(p => p.BlogPost.ACL == null
|| p.BlogPost.ACL.Count == 0)
.Select(p => p.BlogPost).ToArray();
}
var data = posts.OrderByDescending(p => p.DateCreated);
var grouped = data.GroupBy(p => p.Title).Skip(skip).Take(take);
return grouped;
}
public async Task Delete(ClaimsPrincipal user, long id)
{
var uid = user.GetUserId();
BlogPost blog = _context.BlogSpot.Single(m => m.Id == id);
_context.BlogSpot.Remove(blog);
_context.SaveChanges(user.GetUserId());
}
public async Task<IEnumerable<BlogPost>> UserPosts(
string posterName,
string? readerId,
int pageLen = 10,
int pageNum = 0)
{
string? posterId = (await _context.Users.SingleOrDefaultAsync(u => u.UserName == posterName))?.Id ?? null;
if (posterId == null) return Array.Empty<BlogPost>();
return _context.UserPosts(posterId, readerId);
}
public object? ByTitle(string title)
{
return _context.BlogSpot.Include(
b => b.Author
).Where(x => x.Title == title).OrderByDescending(
x => x.DateCreated
).ToList();
}
}

View File

@ -5,8 +5,8 @@ using Yavsc.Models.Access;
namespace Yavsc.ViewModels.Blog
{
public class BlogPostInputViewModel
{
public class BlogPostBase
{
[StringLength(1024)]
public string? Photo { get; set; }
@ -18,9 +18,10 @@ namespace Yavsc.ViewModels.Blog
public string? Content { get; set; }
[InverseProperty("Target")]
[Display(Name="Liste de contrôle d'accès")]
public virtual List<CircleAuthorizationToBlogPost>? ACL { get; set; }
[Display(Name = "Liste de contrôle d'accès")]
public virtual List<CircleAuthorizationToBlogPost>? ACL { get; set; }
public bool Publish { get; set; }
}
}

View File

@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations;
namespace Yavsc.ViewModels.Blog;
public class BlogPostEditViewModel : BlogPostInputViewModel
public class BlogPostEditViewModel : BlogPostBase
{
[Required]

View File

@ -1,22 +1,15 @@
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Authorization;
using Yavsc.Models;
using Yavsc.ViewModels.Auth;
using Microsoft.AspNetCore.Mvc.Rendering;
using Yavsc.Models.Blog;
using Yavsc.Helpers;
using Microsoft.AspNetCore.Localization;
using Microsoft.Extensions.Options;
using Microsoft.EntityFrameworkCore;
using System.Diagnostics;
using Yavsc.ViewModels.Blog;
using System.Collections;
using Yavsc.Server.Exceptions;
// For more information on enabling Web API for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
@ -29,111 +22,63 @@ namespace Yavsc.Controllers
private readonly IAuthorizationService _authorizationService;
readonly RequestLocalizationOptions _localisationOptions;
readonly BlogSpotService blogSpotService;
public BlogspotController(
ApplicationDbContext context,
ILoggerFactory loggerFactory,
IAuthorizationService authorizationService,
IOptions<RequestLocalizationOptions> localisationOptions)
IOptions<RequestLocalizationOptions> localisationOptions,
BlogSpotService blogSpotService)
{
_context = context;
_logger = loggerFactory.CreateLogger<AccountController>();
_authorizationService = authorizationService;
_localisationOptions = localisationOptions.Value;
this.blogSpotService = blogSpotService;
}
// GET: Blog
[AllowAnonymous]
public async Task<IActionResult> Index(string id, int skip=0, int take=25)
public async Task<IActionResult> Index(string id, int skip = 0, int take = 25)
{
if (!string.IsNullOrEmpty(id)) {
return View("UserPosts", await UserPosts(id));
}
IEnumerable<BlogPost> posts;
if (User.Identity.IsAuthenticated)
if (!string.IsNullOrEmpty(id))
{
string viewerId = User.GetUserId();
long[] usercircles = await _context.Circle.Include(c=>c.Members).
Where(c=>c.Members.Any(m=>m.MemberId == viewerId))
.Select(c=>c.Id).ToArrayAsync();
posts = _context.BlogSpot
.Include(b => b.Author)
.Include(p=>p.ACL)
.Include(p=>p.Tags)
.Include(p=>p.Comments)
.Where(p =>(p.ACL.Count == 0)
|| (p.AuthorId == viewerId)
|| (usercircles != null && p.ACL.Any(a => usercircles.Contains(a.CircleId)))
);
return View("UserPosts",
await blogSpotService.UserPosts(id, User.GetUserId(),
skip, take));
}
else
{
posts = _context.BlogSpot
.Include(b => b.Author)
.Include(p=>p.ACL)
.Include(p=>p.Tags)
.Include(p=>p.Comments)
.Where(p => p.ACL.Count == 0 ).ToArray();
}
var data = posts.OrderByDescending( p=> p.DateCreated);
var grouped = data.GroupBy(p=> p.Title).Skip(skip).Take(take);
return View(grouped);
IEnumerable<IGrouping<string,IBlogPost>> byTitle = await this.blogSpotService.IndexByTitle(User, id, skip, take);
return View(byTitle);
}
[Route("~/Title/{id?}")]
[AllowAnonymous]
public IActionResult Title(string id)
{
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
ViewData["Title"] = id;
return View("Title", _context.BlogSpot.Include(
b => b.Author
).Where(x => x.Title == id && (x.AuthorId == uid )).OrderByDescending(
x => x.DateCreated
).ToList());
return View("Title", blogSpotService.ByTitle(id));
}
private async Task<IEnumerable<BlogPost>> UserPosts(string userName, int pageLen=10, int pageNum=0)
private async Task<IEnumerable<BlogPost>> UserPosts(string userName, int pageLen = 10, int pageNum = 0)
{
string posterId = (await _context.Users.SingleOrDefaultAsync(u=>u.UserName == userName))?.Id ?? null ;
return _context.UserPosts(posterId, User.Identity.Name);
return await blogSpotService.UserPosts(userName, User.GetUserId(), pageLen, pageNum);
}
// GET: Blog/Details/5
[AllowAnonymous]
public async Task<IActionResult> Details(long? id)
{
if (id == null)
{
return NotFound();
}
if (id == null) return this.NotFound();
BlogPost blog = _context.BlogSpot
.Include(p => p.Author)
.Include(p => p.Tags)
.Include(p => p.Comments)
.Include(p => p.ACL)
.Single(m => m.Id == id);
if (blog == null)
{
return NotFound();
}
if ( _authorizationService.AuthorizeAsync(User, blog, new ReadPermission()).IsFaulted)
{
return new ChallengeResult();
}
foreach (var c in blog.Comments) {
c.Author = _context.Users.First(u=>u.Id==c.AuthorId);
}
var blog = await blogSpotService.Details(User, id.Value);
ViewData["apicmtctlr"] = "/api/blogcomments";
ViewData["moderatoFlag"] = User.IsInRole(Constants.BlogModeratorGroupName);
return View(blog);
}
void SetLangItems()
{
ViewBag.LangItems = _localisationOptions.SupportedUICultures.Select
ViewBag.LangItems = _localisationOptions.SupportedUICultures?.Select
(
sc => new SelectListItem { Value = sc.IetfLanguageTag, Text = sc.NativeName, Selected = System.Globalization.CultureInfo.CurrentUICulture == sc }
);
@ -143,33 +88,25 @@ namespace Yavsc.Controllers
[Authorize()]
public IActionResult Create(string title)
{
var result = new BlogPostInputViewModel{Title=title
var result = new BlogPostBase
{
Title = title
};
ViewData["PostTarget"]="Create";
SetLangItems();
return View(result);
}
// POST: Blog/Create
[HttpPost, Authorize, ValidateAntiForgeryToken]
public IActionResult Create(BlogPostInputViewModel blogInput)
public IActionResult Create(BlogPostBase blogInput)
{
if (ModelState.IsValid)
{
BlogPost post = new BlogPost
{
Title = blogInput.Title,
Content = blogInput.Content,
Photo = blogInput.Photo,
AuthorId = User.GetUserId()
};
_context.BlogSpot.Add(post);
_context.SaveChanges(User.GetUserId());
BlogPost post = blogSpotService.Create(User.GetUserId(),
blogInput);
return RedirectToAction("Index");
}
ModelState.AddModelError("Unknown","Invalid Blog posted ...");
ViewData["PostTarget"]="Create";
return View("Edit",blogInput);
return View("Edit", blogInput);
}
[Authorize()]
@ -180,26 +117,13 @@ namespace Yavsc.Controllers
{
return NotFound();
}
ViewData["PostTarget"]="Edit";
BlogPost blog = _context.BlogSpot.Include(x => x.Author).Include(x => x.ACL).Single(m => m.Id == id);
if (blog == null)
try
{
return NotFound();
}
if (!_authorizationService.AuthorizeAsync(User, blog, new EditPermission()).IsFaulted)
{
ViewBag.ACL = _context.Circle.Where(
c=>c.OwnerId == blog.AuthorId)
.Select(
c => new SelectListItem
{
Text = c.Name,
Value = c.Id.ToString(),
Selected = blog.AuthorizeCircle(c.Id)
} 
);
BlogPost blog = await blogSpotService.GetPostForEdition(User, id.Value);
if (blog == null)
{
return NotFound();
}
SetLangItems();
return View(new BlogPostEditViewModel
{
@ -208,9 +132,10 @@ namespace Yavsc.Controllers
Content = blog.Content,
ACL = blog.ACL,
Photo = blog.Photo
});
});
}
else
catch (AuthorizationFailureException)
{
return new ChallengeResult();
}
@ -218,65 +143,41 @@ namespace Yavsc.Controllers
// POST: Blog/Edit/5
[HttpPost]
[ValidateAntiForgeryToken,Authorize()]
[ValidateAntiForgeryToken, Authorize()]
public async Task<IActionResult> Edit(BlogPostEditViewModel blogEdit)
{
if (ModelState.IsValid)
{
var blog = _context.BlogSpot.SingleOrDefault(b=>b.Id == blogEdit.Id);
if (blog == null) {
ModelState.AddModelError("Id", "not found");
return View();
}
if (!(await _authorizationService.AuthorizeAsync(User, blog, new EditPermission())).Succeeded) {
ViewData["StatusMessage"] = "Accès restreint";
return new ChallengeResult();
}
blog.Content=blogEdit.Content;
blog.Title = blogEdit.Title;
blog.Photo = blogEdit.Photo;
blog.ACL = blogEdit.ACL;
// saves the change
_context.Update(blog);
_context.SaveChanges(User.GetUserId());
await blogSpotService.Modify(User, blogEdit);
ViewData["StatusMessage"] = "Post modified";
return RedirectToAction("Index");
}
ViewData["PostTarget"]="Edit";
return View(blogEdit);
}
// GET: Blog/Delete/5
[ActionName("Delete"),Authorize()]
public IActionResult Delete(long? id)
[ActionName("Delete"), Authorize()]
public async Task<IActionResult> Delete(long? id)
{
if (id == null)
{
return NotFound();
}
BlogPost blog = _context.BlogSpot.Include(
b => b.Author
).Single(m => m.Id == id);
BlogPost blog = await blogSpotService.GetPostForEdition(User, id.Value);
if (blog == null)
{
return NotFound();
}
return View(blog);
}
// POST: Blog/Delete/5
[HttpPost, ActionName("Delete"), Authorize("IsTheAuthor")]
[HttpPost, ActionName("Delete"), Authorize("TheAuthor")]
[ValidateAntiForgeryToken]
public IActionResult DeleteConfirmed(long id)
public async Task<IActionResult> DeleteConfirmed(long id)
{
var uid = User.GetUserId();
BlogPost blog = _context.BlogSpot.Single(m => m.Id == id);
_context.BlogSpot.Remove(blog);
_context.SaveChanges(User.GetUserId());
await blogSpotService.Delete(User, id);
return RedirectToAction("Index");
}
}

View File

@ -39,7 +39,6 @@ namespace Yavsc.Extensions;
public static class HostingExtensions
{
#region files config
public static IApplicationBuilder ConfigureFileServerApp(this IApplicationBuilder app,
bool enableDirectoryBrowsing = false)
{
@ -91,16 +90,10 @@ public static class HostingExtensions
return app;
}
#endregion
internal static WebApplication ConfigureWebAppServices(this WebApplicationBuilder builder)
{
IServiceCollection services = LoadConfiguration(builder);
//services.AddRazorPages();
services.AddSession();
// TODO .AddServerSideSessionStore<YavscServerSideSessionStore>()
@ -148,7 +141,8 @@ public static class HostingExtensions
.AddTransient<IYavscMessageSender, YavscMessageSender>()
.AddTransient<IBillingService, BillingService>()
.AddTransient<IDataStore, FileDataStore>((sp) => new FileDataStore("googledatastore", false))
.AddTransient<ICalendarManager, CalendarManager>();
.AddTransient<ICalendarManager, CalendarManager>()
.AddTransient<BlogSpotService>();
// TODO for SMS: services.AddTransient<ISmsSender, AuthMessageSender>();
@ -209,7 +203,7 @@ public static class HostingExtensions
// options.AddPolicy("EmployeeId", policy => policy.RequireClaim("EmployeeId", "123", "456"));
// options.AddPolicy("BuildingEntry", policy => policy.Requirements.Add(new OfficeEntryRequirement()));
options.AddPolicy("Authenticated", policy => policy.RequireAuthenticatedUser());
options.AddPolicy("IsTheAuthor", policy => policy.Requirements.Add(new EditPermission()));
options.AddPolicy("TheAuthor", policy => policy.Requirements.Add(new EditPermission()));
})
.AddCors(options =>
{
@ -355,7 +349,7 @@ public static class HostingExtensions
}
internal static WebApplication ConfigurePipeline(this WebApplication app)
internal async static Task<WebApplication> ConfigurePipeline(this WebApplication app)
{
if (app.Environment.IsDevelopment())
@ -365,6 +359,11 @@ public static class HostingExtensions
else
{
app.UseExceptionHandler("/Home/Error");
using (var scope = app.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
await db.Database.MigrateAsync();
}
}
app.UseStaticFiles();

View File

@ -1,6 +1,7 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using RazorEngine.Compilation.ImpromptuInterface.Optimization;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Blog;
@ -55,12 +56,26 @@ public class PermissionHandler : IAuthorizationHandler
return false;
}
private static bool IsOwner(ClaimsPrincipal user, object? resource)
private bool IsOwner(ClaimsPrincipal user, object? resource)
{
if (resource is BlogPost blogPost)
{
return blogPost.AuthorId == user.GetUserId();
}
else
if (resource is DefaultHttpContext httpContext)
{
if (httpContext.Request.Path.StartsWithSegments("/blogpost/Delete", StringComparison.OrdinalIgnoreCase))
{
string postId = (string)httpContext.GetRouteValue("id");
if (long.TryParse(postId, out long id))
{
BlogPost b = applicationDbContext.BlogSpot.FirstOrDefault(b => b.Id == id && b.AuthorId == user.GetUserId());
return b != null;
}
}
}
return false;
}
@ -70,7 +85,7 @@ public class PermissionHandler : IAuthorizationHandler
{
return applicationDbContext.CircleMembers
.Include(c => c.Circle)
.Where(m=>m.MemberId==user.GetUserId() && m.Circle.OwnerId == blogPost.OwnerId)
.Where(m=>m.MemberId==user.GetUserId() && m.Circle.OwnerId == blogPost.AuthorId)
.Any();
}
return true;

View File

@ -6,9 +6,9 @@ namespace Yavsc.Helpers
{
public class AsciidocTagHelper : TagHelper
{
public override async Task ProcessAsync (TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (context.AllAttributes.ContainsName ("summary"))
if (context.AllAttributes.ContainsName("summary"))
{
var summaryLength = context.AllAttributes["summary"].Value;
}
@ -16,12 +16,23 @@ namespace Yavsc.Helpers
var content = await output.GetChildContentAsync();
string text = content.GetContent();
if (string.IsNullOrWhiteSpace(text)) return;
Document document = Document.Parse(text);
var html = document.ToHtml(2);
using var stringWriter = new StringWriter();
html.WriteTo(stringWriter, HtmlEncoder.Default);
var processedHere = stringWriter.ToString();
output.Content.AppendHtml(processedHere);
try
{
Document document = Document.Parse(text);
var html = document.ToHtml(2);
using var stringWriter = new StringWriter();
html.WriteTo(stringWriter, HtmlEncoder.Default);
var processedHere = stringWriter.ToString();
output.Content.AppendHtml(processedHere);
}
catch (ArgumentException ex)
{
// silently render the text
output.Content.AppendHtml("<pre>" + text + "</pre>\n");
// and an error
output.Content.AppendHtml("<pre class=\"parsingError\">" + ex.Message + "</pre>\n");
}
}
}
}

View File

@ -1,6 +1,6 @@
DESTDIR=/srv/www/yavsc
CONFIGURATION=Release
USER=www-data
USER_AND_GROUP=www-data:www-data
SERVICE_PROD=yavsc
DOTNET_FRAMEWORK=net9.0
@ -22,7 +22,7 @@ install_service:
pushInProd: publish
sudo systemctl stop $(SERVICE_PROD)
sudo cp -a bin/$(CONFIGURATION)/$(DOTNET_FRAMEWORK)/publish/* $(DESTDIR)
sudo chown -R $(USER) $(DESTDIR)
sudo chown -R $(USER_AND_GROUP) $(DESTDIR)
sudo sync
sudo systemctl start $(SERVICE_PROD)

View File

@ -6,7 +6,7 @@ namespace Yavsc
{
public class Program
{
public static void Main(string[] args)
public static async Task Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
@ -15,7 +15,7 @@ namespace Yavsc
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables()
.Build();
var app = builder.ConfigureWebAppServices().ConfigurePipeline();
var app = await builder.ConfigureWebAppServices().ConfigurePipeline();
app.UseSession();
app.Run();
}

View File

@ -22,7 +22,7 @@ namespace Yavsc.ViewComponents
{
if (target!=null)
{
var oid = target.OwnerId;
var oid = target.AuthorId;
ViewBag.ACL = dbContext.Circle.Where(
c=>c.OwnerId == oid)
.Select(

View File

@ -1,4 +1,4 @@
@model Yavsc.ViewModels.Blog.BlogPostInputViewModel
@model Yavsc.ViewModels.Blog.BlogPostBase
@{
ViewData["Title"] = "Blog post edition";
@ -47,6 +47,7 @@
</span>
</div>
</div>
<div class="form-group mdcoding">
<label asp-for="Content" class="col-md-2 control-label" ></label>
<div class="col-md-10">
@ -56,6 +57,7 @@
</span>
</div>
</div>
<div class="form-group">
<label asp-for="ACL" class="col-md-2 control-label"></label>
<div class="col-md-10">
@ -63,6 +65,13 @@
</div>
</div>
<div class="form-group">
<label asp-for="Publish" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Publish" class="form-control" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button class="btn btn-primary" >Save</button>

View File

@ -97,6 +97,13 @@
</div>
</div>
<div class="form-group">
<label asp-for="Publish" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Publish" class="form-control" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />

View File

@ -1,4 +1,4 @@
@model IEnumerable<IGrouping<string,BlogPost>>
@model IEnumerable<IGrouping<string,IBlogPost>>
@{
ViewData["Title"] = "Blogs, l'index";
}
@ -47,6 +47,7 @@
<div class="container">
<table class="table">
@foreach (var group in Model) {
var title = group.Key ?? "@";
string secondclass="";
@ -95,6 +96,6 @@
}
</table>
@if(Model.Count()==0){<p>Néant</p>}
</div>

View File

@ -1,14 +1,10 @@
@using Yavsc.Abstract.Identity
@model ApplicationUser
@{
var avuri = "/Avatars/"+Model.UserName+".s.png";
var userPosted = Model.Posts!=null && Model.Posts.Count()>=1;
var avuri = "/Avatars/" + Model.UserName + ".s.png";
}
<div class="userinfo">
@if (userPosted) { <a asp-controller="Blogspot" asp-action="Index"
asp-route-id="@Model.UserName" class="btn btn-primary">
<img src="@avuri" asp-append-version="true" class="smalltofhol" alt="@Model.UserName" title="@Model.UserName"/>
</a>
} else {
Html.DisplayFor(m=>m.UserName);
}
<a title="Posts" asp-controller="Blogspot" asp-action="Index" asp-route-id="@Model.UserName" class="btn btn-primary">
<img src="@avuri" asp-append-version="true" class="smalltofhol" alt="@Model.UserName" title="@Model.UserName" />
</a>
</div>

View File

@ -0,0 +1,10 @@
@using Yavsc.Abstract.Identity
@model IApplicationUser
@{
var avuri = "/Avatars/" + Model.UserName + ".s.png";
}
<div class="userinfo">
<a title="Posts" asp-controller="Blogspot" asp-action="Index" asp-route-id="@Model.UserName" class="btn btn-primary">
<img src="@avuri" asp-append-version="true" class="smalltofhol" alt="@Model.UserName" title="@Model.UserName" />
</a>
</div>

View File

@ -18,7 +18,6 @@
<ul class="dropdown-menu" aria-labelledby="dropdown04">
<li><a class="dropdown-item" asp-controller="Bug" asp-action="Index">Bugs</a></li>
<li><a class="dropdown-item" asp-controller="HyperLink" asp-action="Index">HyperLink</a></li>
<li><a class="dropdown-item" asp-controller="LiveFlow" asp-action="Index">LiveFlow</a></li>
<li><a class="dropdown-item" asp-controller="Feature" asp-action="Index">Features</a></li>
</ul>
</li>

View File

@ -29,7 +29,7 @@
"jquery-validation": ">=1.19"
},
"devDependencies": {
"gulp": "^5.0.1",
"gulp": "^4.0.2",
"gulp-line-ending-corrector": "^1.0.3",
"gulp-rename": "~2.0.0",
"gulp-replace": "~1.1.3",