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
1407 changed files with 237169 additions and 33506 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

1
.gitignore vendored
View File

@ -7,6 +7,7 @@
.paket/
.vs/
.sass-cache/
.private/
/out
bin

2
.vscode/launch.json vendored
View File

@ -43,7 +43,7 @@
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/src/Yavsc/bin/Debug/net8.0/Yavsc.dll",
"program": "${workspaceFolder}/src/Yavsc/bin/Debug/net9.0/Yavsc.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Yavsc",
"stopAtEntry": false,

View File

@ -17,15 +17,15 @@ C'est une application mettant en oeuvre une prise de contact entre un demandeur
et, pour execution en environement de développement
```
~/workspace/yavsc/Yavsc @ ASPNETCORE_ENV=Development dotnet run
```bash
~/workspace/yavsc/Yavsc @ ASPNETCORE_ENV=Development dotnet run
```
## Tests
Utilisez GNU/Makefile (et visitez le code, dans le dossier `test` ):
[TOREDO] Depuis le répertoire racine:
[TODO] Depuis le répertoire racine:
```bash
make test
@ -33,13 +33,14 @@ make test
## Installation / Déploiment / Développement
### les services kestrel et kestrel-pre
[TODO]
### les services et l'API
### La Prod
Une fois sûr de vous, et une fois que Git dit propre votre copie de travail, depuis le répertoire `Yavsc`, lancez `make pushInProd`.
`cd srv/Yavsc` : `make pushInProd CONFIGURATION=Release`.
puis, pour une première installation
`make install_service`.
## Fonctionalités (encore en cours de développement)

27
contrib/yavsc.service Normal file
View File

@ -0,0 +1,27 @@
[Unit]
Description=Yavsc
After=syslog.target
After=network.target
Wants=postgresql.service
After=postgresql.service
[Service]
RestartSec=5s
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/srv/www/yavsc/
ExecStart=/srv/www/yavsc/Yavsc
Restart=always
Environment="HOME=/srv/www/yavsc"
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=yavsc
[Install]
WantedBy=multi-user.target

View File

@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>1c73094f-959f-4211-b1a1-6a69b236c283</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.13" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.6" />
<ProjectReference Include="../Yavsc.Server/Yavsc.Server.csproj" />
</ItemGroup>
</Project>

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

@ -19,6 +19,7 @@
// 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 Yavsc.Abstract.Models.Messaging;
using Yavsc.Models.Messaging;
namespace Yavsc.Models.Google.Messaging

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

@ -5,8 +5,8 @@ namespace Yavsc
public interface ITrackedEntity
{
DateTime DateCreated { get; set; }
string UserCreated { get; set; }
string? UserCreated { get; set; }
DateTime DateModified { get; set; }
string UserModified { get; set; }
string? UserModified { get; set; }
}
}

View File

@ -2,7 +2,7 @@ using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Yavsc.Models.Messaging
namespace Yavsc.Abstract.Models.Messaging
{
/// <summary>
/// A Notification, that mocks the one sent to Google,
@ -29,25 +29,25 @@ namespace Yavsc.Models.Messaging
/// </summary>
[StringLength(512)]
[Display(Name = "Icône")]
public string icon { get; set; }
public string? icon { get; set; }
/// <summary>
/// The sound.
/// </summary>
[StringLength(512)]
[Display(Name = "Son")]
public string sound { get; set; }
public string? sound { get; set; }
/// <summary>
/// The tag.
/// </summary>
[StringLength(512)]
[Display(Name = "Tag")]
public string tag { get; set; }
public string? tag { get; set; }
/// <summary>
/// The color.
/// </summary>
[StringLength(512)]
[Display(Name = "Couleur")]
public string color { get; set; }
public string? color { get; set; }
/// <summary>
/// The click action.
/// </summary>
@ -63,7 +63,7 @@ namespace Yavsc.Models.Messaging
/// </summary>
/// <returns></returns>
[StringLength(512)]
public string Target { get; set; }
public string? Target { get; set; }
public Notification()
{

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<TargetFrameworks>net9.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Description> A shared model for a little client/server app, dealing about establishing some contract, between some human client and provider.

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,51 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Yavsc.Migrations
{
/// <inheritdoc />
public partial class notificationTarget : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Visible",
table: "BlogSpot");
migrationBuilder.AlterColumn<string>(
name: "Target",
table: "Notification",
type: "character varying(512)",
maxLength: 512,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Target",
table: "Notification",
type: "character varying(512)",
maxLength: 512,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512,
oldNullable: true);
migrationBuilder.AddColumn<bool>(
name: "Visible",
table: "BlogSpot",
type: "boolean",
nullable: false,
defaultValue: false);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,109 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Yavsc.Migrations
{
/// <inheritdoc />
public partial class notificationNulls : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "tag",
table: "Notification",
type: "character varying(512)",
maxLength: 512,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512);
migrationBuilder.AlterColumn<string>(
name: "sound",
table: "Notification",
type: "character varying(512)",
maxLength: 512,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512);
migrationBuilder.AlterColumn<string>(
name: "icon",
table: "Notification",
type: "character varying(512)",
maxLength: 512,
nullable: true,
defaultValue: "exclam",
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512,
oldDefaultValue: "exclam");
migrationBuilder.AlterColumn<string>(
name: "color",
table: "Notification",
type: "character varying(512)",
maxLength: 512,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "tag",
table: "Notification",
type: "character varying(512)",
maxLength: 512,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "sound",
table: "Notification",
type: "character varying(512)",
maxLength: 512,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "icon",
table: "Notification",
type: "character varying(512)",
maxLength: 512,
nullable: false,
defaultValue: "exclam",
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512,
oldNullable: true,
oldDefaultValue: "exclam");
migrationBuilder.AlterColumn<string>(
name: "color",
table: "Notification",
type: "character varying(512)",
maxLength: 512,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512,
oldNullable: true);
}
}
}

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 trackedNulls : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Yavsc.Migrations
{
/// <inheritdoc />
public partial class blogNulls : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "UserModified",
table: "BlogSpot",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");
migrationBuilder.AlterColumn<string>(
name: "UserCreated",
table: "BlogSpot",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "UserModified",
table: "BlogSpot",
type: "text",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "UserCreated",
table: "BlogSpot",
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,40 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Yavsc.Migrations
{
/// <inheritdoc />
public partial class BlogPostInputViewModelNulls : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Content",
table: "BlogSpot",
type: "character varying(56224)",
maxLength: 56224,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(56224)",
oldMaxLength: 56224);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Content",
table: "BlogSpot",
type: "character varying(56224)",
maxLength: 56224,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "character varying(56224)",
oldMaxLength: 56224,
oldNullable: true);
}
}
}

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

@ -17,7 +17,7 @@ namespace Yavsc.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.2")
.HasAnnotation("ProductVersion", "9.0.6")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
@ -183,6 +183,56 @@ namespace Yavsc.Migrations
b.ToTable("ClientProviderInfo");
});
modelBuilder.Entity("Yavsc.Abstract.Models.Messaging.Notification", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("Target")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<string>("body")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<string>("click_action")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<string>("color")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<string>("icon")
.ValueGeneratedOnAdd()
.HasMaxLength(512)
.HasColumnType("character varying(512)")
.HasDefaultValue("exclam");
b.Property<string>("sound")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<string>("tag")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<string>("title")
.IsRequired()
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.HasKey("Id");
b.ToTable("Notification");
});
modelBuilder.Entity("Yavsc.Models.Access.Ban", b =>
{
b.Property<long>("Id")
@ -711,7 +761,6 @@ namespace Yavsc.Migrations
.HasColumnType("text");
b.Property<string>("Content")
.IsRequired()
.HasMaxLength(56224)
.HasColumnType("character varying(56224)");
@ -725,22 +774,20 @@ namespace Yavsc.Migrations
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<bool>("Publish")
.HasColumnType("boolean");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<string>("UserCreated")
.IsRequired()
.HasColumnType("text");
b.Property<string>("UserModified")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("Visible")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("AuthorId");
@ -813,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")
@ -1079,7 +1136,6 @@ namespace Yavsc.Migrations
.HasColumnType("numeric");
b.Property<string>("ScheduleOwnerId")
.IsRequired()
.HasColumnType("text");
b.Property<decimal>("ShampooPrice")
@ -1602,61 +1658,6 @@ namespace Yavsc.Migrations
b.ToTable("DismissClicked");
});
modelBuilder.Entity("Yavsc.Models.Messaging.Notification", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("Target")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<string>("body")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<string>("click_action")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<string>("color")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<string>("icon")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(512)
.HasColumnType("character varying(512)")
.HasDefaultValue("exclam");
b.Property<string>("sound")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<string>("tag")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<string>("title")
.IsRequired()
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.HasKey("Id");
b.ToTable("Notification");
});
modelBuilder.Entity("Yavsc.Models.Musical.Instrument", b =>
{
b.Property<long>("Id")
@ -2092,7 +2093,6 @@ namespace Yavsc.Migrations
.HasColumnType("boolean");
b.Property<string>("ModeratorGroupName")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
@ -2103,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");
@ -2780,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")
@ -2851,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()
@ -3057,7 +3062,7 @@ namespace Yavsc.Migrations
modelBuilder.Entity("Yavsc.Models.Messaging.DismissClicked", b =>
{
b.HasOne("Yavsc.Models.Messaging.Notification", "Notified")
b.HasOne("Yavsc.Abstract.Models.Messaging.Notification", "Notified")
.WithMany()
.HasForeignKey("NotificationId")
.OnDelete(DeleteBehavior.Cascade)

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;
@ -40,6 +34,8 @@ namespace Yavsc.Models
using Yavsc.Server.Models.Calendar;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Yavsc.Abstract.Models.Messaging;
using Org.BouncyCastle.Asn1.Crmf;
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
@ -50,7 +46,7 @@ namespace Yavsc.Models
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
@ -60,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);
@ -80,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())
{
@ -88,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();
}
@ -124,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
@ -225,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))
{
@ -281,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
@ -294,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; }
@ -303,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")]
@ -35,7 +38,7 @@ namespace Yavsc.Models.Blog
}
[Display(Name="Créateur")]
public string UserCreated
public string? UserCreated
{
get; set;
}
@ -47,7 +50,7 @@ namespace Yavsc.Models.Blog
}
[Display(Name="Utilisateur ayant modifé le dernier")]
public string UserModified
public string? UserModified
{
get; set;
}
@ -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

@ -1,5 +1,6 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Yavsc.Abstract.Models.Messaging;
using Yavsc.Attributes.Validation;
namespace Yavsc.Models.Messaging

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,21 +5,23 @@ using Yavsc.Models.Access;
namespace Yavsc.ViewModels.Blog
{
public class BlogPostInputViewModel
{
public class BlogPostBase
{
[StringLength(1024)]
public string? Photo { get; set; }
[StringLength(1024)]
[Required]
public string Title { get; set; }
[StringLength(56224)]
public string Content { get; set; }
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,30 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UserSecretsId>53bd70e8-ff81-497a-847f-a15fd8ea7a09</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.11" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
<PackageReference Include="HigginsSoft.IdentityServer8" Version="8.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.6" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="9.0.6" />
<PackageReference Include="Microsoft.AspNetCore.Http.Features" Version="5.0.17" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.2">
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.6">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.3.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.2" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.6" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="9.0.0" />
<PackageReference Include="Google.Apis.Calendar.v3" Version="1.60.0.2993" />
<PackageReference Include="PayPalMerchantSDK" Version="2.16.250" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.9" />
<PackageReference Include="RazorEngine.NetCore" Version="3.1.0" />
<PackageReference Include="MailKit" Version="4.3.0" />
<PackageReference Include="MimeKit" Version="4.7.1" />
<PackageReference Include="MailKit" Version="4.12.1" />
<PackageReference Include="MimeKit" Version="4.12.0" />
<PackageReference Include="pazof.rules" Version="1.1.3" />
</ItemGroup>
<ItemGroup>

169
src/Yavsc/"BlogSpot" Normal file
View File

@ -0,0 +1,169 @@
\dt
select user,password from users;
select user,passwd from users;
select user from users;
select username,pwd from users;
select username,passwd from users;
select username,password from users;
\dT users
\d users
select username,passwd from users;
select username,passd from users;
\d users
select username,passw from users;
\d profiledata
select gregid from profiledata;
select uniqueid,gregid from profiledata;
select uniqueid,username from profile;
select uniqueid,username from profiles;
select uniqueid,gregid from profiledata;
select uniqueid,username from profiles;
select uniqueid,gregid from profiledata;
select uniqueid,gregid from profiledata;
select uniqueid,gregid from profiledata;
select uniqueid,gregid from profiledata;
select uniqueid,gregid from profiledata;
drop table GitRepositoryReference;
\use YavscDev
\use
\?
\use \?
\dt
drop table "GitRepositoryReference";
drop table "GitRepositoryReference" CASCADE;
exit;
\q
delete from "Project"
;
\q
create database dotnetmvc
;
create user dotnetmvc ;
grant CREATE on paul;
grant admins TO paul;
grant CREATE TO paul;
grant postgres TO paul;
grant paul TO postgres;
commit;
CREATE ROLE baget nocreatedb nocreaterole noreplication;
CREATE ROLE baget nocreatedb nocreaterole noreplication;
CREATE ROLE baget nocreatedb nocreaterole noreplication;
DROP ROLE baget;
commit;
alter role baget with superuser
;
commit;
\dT Project
\dt Project
\dt "Project"
desc "Project"
\?
\d "Project"
\d BlogSpot
\d Blogspot
\d "Blogspot"
\d "BlogSpot"
\d "BlogPost"
\d "BlogPost"
\d "BlogPost"
\d "BlogPost"
\d "BlogPost"
\d AspNetUsers
\d "AspNetUsers"
\dT "AspNetUsers"
update "AspNetUsers" set "LockoutEnable" = false;
\d "AspNetUsers"
\d "AspNetUsers"
update "AspNetUsers" set "LockoutEnabled" = false;
commit ;
\quit
update "AspNetUsers" set "LockoutEnabled" = true;
\s
\d
\dT
\?
\dn
\?
\?
\conninfo
\h create database
\h create user
create user forgejo with login 'ogVZ)f#m85zx';
create user forgejo with login;
\h alter user
alter user forgejo with PASSWORD 'ogVZ)f#m85zx';
commit:
commit;
commit;
\h create databse
\h create databse
create database forgejo with owner forgejo;
create user woodpecker with password 'aormb%$98zv<U&@' ;'
\sd
\?d
\dd
\dT
\dt
\d
\dd
\?
\dS
\?
\dD
\?
\dg
\?
\dn
\?
\l
\dl
\l
\dg
create database woodpecker with OWNER 'woodpecker';
select count(*) from "Users"
;
select count(*) from "AspNetUsers";
desc "AspNetUsers";
\dT "AspNetUsers"
\d "AspNetUsers"
update "AspNetUsers" set "EmailConfirmed" = true;
commit
;
select "UserName" from "AspNetUsers" ;
desc "AspNetUsers"
\d "AspNetUsers"
select "UserName", "Email" from "AspNetUsers" ;
select "UserName", "Email" from "AspNetUsers" ;
\d "AspNetUsers"
select "Id", "UserName", "Email" from "AspNetUsers" ;
\d "AspNetUsers"
select "Id", "UserName", "Email", "ConfirmedEmail" from "AspNetUsers" ;
\d "AspNetUsers"
select "Id", "UserName", "Email", "EmailConfirmed" from "AspNetUsers" ;
select * from "AspNetUsers" ;
\d "AspNetUsers"
select "Id", "UserName", "Email", "EmailConfirmed", "LockoutEnabe" from "AspNetUsers" ;
\d "AspNetUsers"
select "Id", "UserName", "Email", "EmailConfirmed", "LockoutEnabled" from "AspNetUsers" ;
upate AspNetUsers set LockoutEnabled = false;
update AspNetUsers set LockoutEnabled = false;
update "AspNetUsers" set "LockoutEnabled" = false;
commit;
select "Id", "UserName", "Email", "EmailConfirmed", "LockoutEnabled" from "AspNetUsers" ;
SELECT a."Id", a."AccessFailedCount", a."AllowMonthlyEmail", a."Avatar", a."BankInfoId", a."ConcurrencyStamp", a."DedicatedGoogleCalendar", a."DiskQuota", a."DiskUsage", a."Email", a."EmailConfirmed", a."FullName", a."LockoutEnabled", a."LockoutEnd", a."MaxFileSize", a."NormalizedEmail", a."NormalizedUserName", a."PasswordHash", a."PhoneNumber", a."PhoneNumberConfirmed", a."PostalAddressId", a."SecurityStamp", a."TwoFactorEnabled", a."UserName"
FROM "AspNetUsers" AS a
WHERE a."Email" = 'paul@pschneider.fr';
update "AspNetUsers" set "UserName" = 'Paul' where "Email" = 'paul@pschneider.fr';
update "AspNetUsers" set "UserName" = 'PaulS' where "Email" = 'contact@pschneider.fr';
update "AspNetUsers" set "UserName" = 'PaulSc' where "Email" = 'redienhcs.luap@gmail.com';
delete from Users where "userName" = 'pa'
;
delete from "Users" where "UserName" = 'pa';
delete from "AspNetUsers" where "UserName" = 'pa';
select "Id", "UserName", "Email", "EmailConfirmed", "LockoutEnabled" from "AspNetUsers" ;
\dT
\d
alter table "Activity" rename to "Activities";
\d
alter table "BlogPost" rename to "BlogSpot";
\s "BlogSpot"

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

@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Yavsc.Abstract.Models.Messaging;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Messaging;

View File

@ -25,6 +25,7 @@ namespace Yavsc.Controllers
using Microsoft.AspNetCore.Identity.UI.Services;
using Yavsc.Interface;
using Yavsc.Settings;
using Yavsc.Abstract.Models.Messaging;
public class HairCutCommandController : CommandController
{

View File

@ -48,9 +48,6 @@ namespace Yavsc.Controllers
);
if (notes.Any()) this.Notify(notes);
ViewData["HaircutCommandCount"] = _dbContext.HairCutQueries.Where(
q => q.ClientId == uid && q.Status < QueryStatus.Failed
).Count();
var toShow = _dbContext.Activities
.Include(a => a.Forms)
.Include(a => a.Parent)

View File

@ -32,13 +32,13 @@ using Yavsc.ViewModels.Auth;
using Yavsc.Server.Helpers;
using System.Security.Cryptography;
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Protocols.Configuration;
namespace Yavsc.Extensions;
public static class HostingExtensions
{
#region files config
public static IApplicationBuilder ConfigureFileServerApp(this IApplicationBuilder app,
bool enableDirectoryBrowsing = false)
{
@ -90,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>()
@ -147,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>();
@ -208,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 =>
{
@ -304,7 +299,8 @@ public static class HostingExtensions
{
var path = builder.Configuration["SigningCert:Path"];
var pass = builder.Configuration["SigningCert:Password"];
Debug.Assert(path != null);
if (path == null)
throw new InvalidConfigurationException("No signing cert path");
FileInfo certFileInfo = new FileInfo(path);
Debug.Assert(certFileInfo.Exists);
RSA rsa = RSA.Create();
@ -353,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())
@ -363,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

@ -70,6 +70,11 @@ namespace Yavsc.Helpers
{
switch (elt.GetType().FullName)
{
case "AsciiDocNet.Monospace":
sb.AppendHtml("<code>");
Monospace mono = (Monospace)elt;
AllItemsToHtml(sb, mono);
break;
case "AsciiDocNet.Link":
Link link = (Link)elt;
Uri uri;
@ -98,11 +103,8 @@ namespace Yavsc.Helpers
case "AsciiDocNet.Strong":
sb.AppendHtml("<b>");
AsciiDocNet.Strong str = (Strong)elt;
foreach (var stritem in str)
{
stritem.ToHtml(sb);
}
Strong str = (Strong)elt;
AllItemsToHtml(sb, str);
sb.AppendHtml("</b>");
break;
case "AsciiDocNet.InternalAnchor":
@ -138,10 +140,35 @@ namespace Yavsc.Helpers
default:
string unsupportedType = elt.GetType().FullName;
throw new InvalidProgramException(unsupportedType);
if (elt is InlineContainer inlineContainer)
{
sb.AppendHtml($"<span title=\"E NOT SUPPORTED : {unsupportedType}\">");
AllItemsToHtml(sb, inlineContainer);
sb.AppendHtml("</span>");
}
else if (elt is IInlineElement inlineElement)
{
sb.AppendHtml($"<span title=\"E NOT SUPPORTED : {unsupportedType}\">");
RenderLitteral(inlineElement, sb);
sb.AppendHtml("</span>");
}
else
{
throw new InvalidProgramException(unsupportedType);
}
break;
}
}
private static void AllItemsToHtml(IHtmlContentBuilder sb, InlineContainer mono)
{
foreach (var item in mono)
{
item.ToHtml(sb);
}
sb.AppendHtml("</code>");
}
private static void RenderLitteral(IInlineElement elt, IHtmlContentBuilder sb)
{
var tl = elt as TextLiteral;
@ -173,39 +200,39 @@ namespace Yavsc.Helpers
return contentbuilder;
}
/*
public static IHtmlContent AsciiDocFor<TModel>(this IHtmlHelper<TModel> html,
Expression<Func<TModel, string>> expression)
{
string ascii = html.ValueFor<string>(expression, "{0}");
if (string.IsNullOrWhiteSpace(ascii))
return new HtmlString(string.Empty);
Document document = Document.Parse(ascii);
var htmlDoc = document.ToHtml();
var span = new TagBuilder("p") { TagRenderMode = TagRenderMode.SelfClosing };
span.InnerHtml.AppendHtml(htmlDoc);
return span.RenderBody();
}
/*
public static IHtmlContent AsciiDocFor<TModel>(this IHtmlHelper<TModel> html,
Expression<Func<TModel, string>> expression)
{
string ascii = html.ValueFor<string>(expression, "{0}");
if (string.IsNullOrWhiteSpace(ascii))
return new HtmlString(string.Empty);
Document document = Document.Parse(ascii);
var htmlDoc = document.ToHtml();
var span = new TagBuilder("p") { TagRenderMode = TagRenderMode.SelfClosing };
span.InnerHtml.AppendHtml(htmlDoc);
return span.RenderBody();
}
public static string AsciiDoc(IHtmlHelper<BlogPost> htmlHelper, string text)
{
return AsciiDoc(htmlHelper, text, null);
}
public static string AsciiDoc(IHtmlHelper<BlogPost> htmlHelper, string text)
{
return AsciiDoc(htmlHelper, text, null);
}
private static string AsciiDoc(IHtmlHelper<BlogPost> htmlHelper, string text, object htmlAttributes)
{
// Create tag builder
var builder = new TagBuilder("div");
var document = Document.Parse(text);
private static string AsciiDoc(IHtmlHelper<BlogPost> htmlHelper, string text, object htmlAttributes)
{
// Create tag builder
var builder = new TagBuilder("div");
var document = Document.Parse(text);
// builder.InnerHtml = .
// builder.InnerHtml = .
// Add attributes
builder.MergeAttribute("class", "ascii");
builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
// Add attributes
builder.MergeAttribute("class", "ascii");
builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
// Render tag
return builder.ToString();
} */
// Render tag
return builder.ToString();
} */
}
}

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 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Yavsc.Models.Messaging;
using Yavsc.Abstract.Models.Messaging;
namespace Yavsc.Helpers
{

View File

@ -1,36 +1,33 @@
DESTDIR=/srv/www/yavsc
HOSTING=localhost
ASPNET_LOG_LEVEL=debug
SOURCE_DIR=../..
USER=www-data
HOSTING_PRE=yavsv.pschneider.fr
CONFIGURATION=Debug
SERVICE_PRE=Yavsc
CONFIGURATION=Release
USER_AND_GROUP=www-data:www-data
SERVICE_PROD=yavsc
DOTNET_FRAMEWORK=net9.0
all:
dotnet build
showConfig:
@echo HOSTING_PRE: $(USER)@$(HOSTING_PRE)
@echo CONFIGURATION: $(CONFIGURATION)
@echo DESTDIR: $(DESTDIR)
@echo SERVICE_PRE: $(SERVICE_PRE)
@echo SERVICE_PROD: $(SERVICE_PROD)
publish:
ASPNETCORE_ENV=$(CONFIGURATION) dotnet publish
pushInPre: publish
sudo service $(SERVICE_PRE) stop
sudo cp -a bin/Debug/net7.0/publish/* $(DESTDIR)
sudo chown -R $(USER) $(DESTDIR)
install_service:
sudo cp ../../contrib/yavsc.service /etc/systemd/system
sudo systemctl enable yavsc
pushInProd: publish
sudo systemctl stop $(SERVICE_PROD)
sudo cp -a bin/$(CONFIGURATION)/$(DOTNET_FRAMEWORK)/publish/* $(DESTDIR)
sudo chown -R $(USER_AND_GROUP) $(DESTDIR)
sudo sync
sudo service $(SERVICE_PRE) start
sudo systemctl start $(SERVICE_PROD)
%.min.js: %.js
jsmin < $^ > $@
%.min.css: %.css
jsmin < $^ > $@
%.Designer.cs: %.resx
strongresbuildercli -l -p -t -r "Yavsc.Resources." $^

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

@ -80,11 +80,6 @@
<li><a asp-controller="Announces" class="badge" >
<img src="@SiteSettings.Value.Logo" alt="announces" title="Annonces @SiteSettings.Value.Title" /></a></li>
}
@if ((int)ViewData["HaircutCommandCount"]>0) {
<li><a asp-controller="HairCutCommand" class="badge" >
<img src="~/images/shoppingcart.svg" alt="basket" title="Vos bons de commande" />(@ViewData["HaircutCommandCount"])</a></li>
}
}
@section header {
<script src="~/lib/bootstrap/js/carousel.js" asp-append-version="true"></script>

View File

@ -1,4 +1,4 @@
@model Yavsc.Models.Messaging.Notification
@model Notification
@{
ViewData["Title"] = "Create";

View File

@ -1,4 +1,4 @@
@model Yavsc.Models.Messaging.Notification
@model Notification
@{
ViewData["Title"] = "Delete";

View File

@ -1,4 +1,4 @@
@model Yavsc.Models.Messaging.Notification
@model Notification
@{
ViewData["Title"] = "Details";

View File

@ -1,4 +1,4 @@
@model Yavsc.Models.Messaging.Notification
@model Notification
@{
ViewData["Title"] = "Edit";

View File

@ -1,4 +1,4 @@
@model IEnumerable<Yavsc.Models.Messaging.Notification>
@model IEnumerable<Notification>
@{
ViewData["Title"] = "Index";

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

@ -11,6 +11,7 @@
@using Yavsc.Models.Auth;
@using Yavsc.Models.Identity;
@using Yavsc.Models.Access;
@using Yavsc.Abstract.Models.Messaging;
@using Yavsc.Billing;
@using Yavsc.Server.Models.Calendar;
@using Yavsc.ViewModels.Blog;
@ -28,7 +29,6 @@
@using Microsoft.AspNetCore.Html;
@using Microsoft.AspNetCore.Identity;
@using Yavsc.Helpers;
@using PayPal.PayPalAPIInterfaceService.Model;
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<PackageLicenseExpression>WTFPL</PackageLicenseExpression>
@ -15,33 +15,34 @@
</PackageReference>
<PackageReference Include="HigginsSoft.IdentityServer8.AspNetIdentity" Version="8.0.4" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="8.0.13" />
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="9.0.6" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="8.0.13" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.13" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.13" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.13">
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.6" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="9.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.6">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.13">
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.6">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.13" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.13" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.6" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.6" />
<PackageReference Include="Google.Apis.Compute.v1" Version="1.54.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Razor" Version="2.2.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.7" />
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Antiforgery" Version="2.2.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Razor" Version="2.3.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="9.0.0" />
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.6" />
<PackageReference Include="Microsoft.AspNetCore.Antiforgery" Version="2.3.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.4" />
<PackageReference Include="AsciiDocNet" Version="1.0.0-alpha6" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.9" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../Yavsc.Server/Yavsc.Server.csproj" />
<ProjectReference Include="../Yavsc.Abstract/Yavsc.Abstract.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<key id="afbdf233-abc3-4762-865b-884187518d95" version="1">
<creationDate>2025-06-13T12:15:54.5621476Z</creationDate>
<activationDate>2025-06-13T12:15:54.558788Z</activationDate>
<expirationDate>2025-09-11T12:15:54.558788Z</expirationDate>
<descriptor deserializerType="Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60">
<descriptor>
<encryption algorithm="AES_256_CBC" />
<validation algorithm="HMACSHA256" />
<masterKey p4:requiresEncryption="true" xmlns:p4="http://schemas.asp.net/2015/03/dataProtection">
<!-- Warning: the key below is in an unencrypted form. -->
<value>mNS2X6pB+1DLQ8JaiXInlPJF6xFGLIRrMtgLF1oRfJ/60kCHY7OJuu/NOD18mxOTQEUj/IoHBM3PCAnGwiRG4Q==</value>
</masterKey>
</descriptor>
</descriptor>
</key>

View File

@ -1,8 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Yavsc.Abstract\Yavsc.Abstract.csproj" />
<PackageReference Include="IdentityModel.AspNetCore" Version="4.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.13" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.6" />
</ItemGroup>
<ItemGroup>
@ -12,10 +18,4 @@
</Content>
</ItemGroup>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,12 @@
module.exports = {
presets: [
[
'@babel/preset-env',
{
loose: true,
bugfixes: true,
modules: false
}
]
]
};

View File

@ -1,44 +1,15 @@
{
"name": "bootstrap",
"description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
"keywords": [
"css",
"js",
"less",
"mobile-first",
"responsive",
"front-end",
"framework",
"web"
],
"homepage": "http://getbootstrap.com",
"license": "MIT",
"moduleType": "globals",
"main": [
"less/bootstrap.less",
"dist/js/bootstrap.js"
],
"ignore": [
"/.*",
"_config.yml",
"CNAME",
"composer.json",
"CONTRIBUTING.md",
"docs",
"js/tests",
"test-infra"
],
"dependencies": {
"jquery": ">= 1.9.1"
},
"version": "3.3.5",
"_release": "3.3.5",
"homepage": "https://github.com/twbs/bootstrap",
"version": "5.3.6",
"_release": "5.3.6",
"_resolution": {
"type": "version",
"tag": "v3.3.5",
"commit": "16b48259a62f576e52c903c476bd42b90ab22482"
"tag": "v5.3.6",
"commit": "f849680d16a9695c9a6c9c062d6cff55ddcf071e"
},
"_source": "https://github.com/twbs/bootstrap.git",
"_target": "3.3.5",
"_originalSource": "bootstrap"
"_target": "^5.3.6",
"_originalSource": "bootstrap",
"_direct": true
}

View File

@ -0,0 +1,12 @@
# https://github.com/browserslist/browserslist#readme
>= 0.5%
last 2 major versions
not dead
Chrome >= 60
Firefox >= 60
Firefox ESR
iOS >= 12
Safari >= 12
not Explorer <= 11
not kaios <= 2.5 # fix floating label issues in Firefox (see https://github.com/postcss/autoprefixer/issues/1533)

View File

@ -0,0 +1,66 @@
{
"files": [
{
"path": "./dist/css/bootstrap-grid.css",
"maxSize": "6.5 kB"
},
{
"path": "./dist/css/bootstrap-grid.min.css",
"maxSize": "6.0 kB"
},
{
"path": "./dist/css/bootstrap-reboot.css",
"maxSize": "3.5 kB"
},
{
"path": "./dist/css/bootstrap-reboot.min.css",
"maxSize": "3.25 kB"
},
{
"path": "./dist/css/bootstrap-utilities.css",
"maxSize": "11.75 kB"
},
{
"path": "./dist/css/bootstrap-utilities.min.css",
"maxSize": "10.75 kB"
},
{
"path": "./dist/css/bootstrap.css",
"maxSize": "32.5 kB"
},
{
"path": "./dist/css/bootstrap.min.css",
"maxSize": "30.25 kB"
},
{
"path": "./dist/js/bootstrap.bundle.js",
"maxSize": "43.0 kB"
},
{
"path": "./dist/js/bootstrap.bundle.min.js",
"maxSize": "23.5 kB"
},
{
"path": "./dist/js/bootstrap.esm.js",
"maxSize": "28.0 kB"
},
{
"path": "./dist/js/bootstrap.esm.min.js",
"maxSize": "18.25 kB"
},
{
"path": "./dist/js/bootstrap.js",
"maxSize": "28.75 kB"
},
{
"path": "./dist/js/bootstrap.min.js",
"maxSize": "16.25 kB"
}
],
"ci": {
"trackBranches": [
"main",
"v4-dev"
]
}
}

View File

@ -0,0 +1,131 @@
{
"version": "0.2",
"words": [
"affordance",
"allowfullscreen",
"Analyser",
"autohide",
"autohiding",
"autoplay",
"autoplays",
"autoplaying",
"blazingly",
"Blockquotes",
"Bootstrappers",
"borderless",
"Brotli",
"browserslist",
"browserslistrc",
"btncheck",
"btnradio",
"callout",
"callouts",
"camelCase",
"clearfix",
"Codesniffer",
"combinator",
"Contentful",
"Cpath",
"Crossfade",
"crossfading",
"cssgrid",
"Csvg",
"Datalists",
"Deque",
"discoverability",
"docsearch",
"docsref",
"dropend",
"dropleft",
"dropright",
"dropstart",
"dropup",
"dgst",
"errorf",
"favicon",
"favicons",
"fieldsets",
"flexbox",
"fullscreen",
"getbootstrap",
"Grayscale",
"Hoverable",
"hreflang",
"hstack",
"importmap",
"jsdelivr",
"Jumpstart",
"keyframes",
"libera",
"libman",
"Libsass",
"lightboxes",
"Lowercased",
"markdownify",
"mediaqueries",
"minifiers",
"misfunction",
"mkdir",
"monospace",
"mouseleave",
"navbars",
"navs",
"Neue",
"noindex",
"Noto",
"offcanvas",
"offcanvases",
"Packagist",
"popperjs",
"prebuild",
"prefersreducedmotion",
"prepended",
"printf",
"rects",
"relref",
"rgba",
"roboto",
"RTLCSS",
"ruleset",
"sassrc",
"screenreaders",
"scrollbars",
"scrollspy",
"Segoe",
"semibold",
"socio",
"srcset",
"stackblitz",
"stickied",
"Stylelint",
"subnav",
"tabbable",
"textareas",
"toggleable",
"topbar",
"touchend",
"twbs",
"unitless",
"unstylable",
"unstyled",
"Uppercased",
"urlize",
"urlquery",
"vbtn",
"viewports",
"Vite",
"vstack",
"walkthroughs",
"WCAG",
"zindex"
],
"language": "en-US",
"ignorePaths": [
".cspell.json",
"dist/",
"*.min.*",
"**/*rtl*",
"**/tests/**"
],
"useGitignore": true
}

View File

@ -0,0 +1,11 @@
# editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

View File

@ -0,0 +1,9 @@
**/*.min.js
**/dist/
**/vendor/
/_site/
/site/public/
/js/coverage/
/site/static/sw.js
/site/static/docs/**/assets/sw.js
/site/layouts/partials/

View File

@ -0,0 +1,240 @@
{
"root": true,
"extends": [
"plugin:import/errors",
"plugin:import/warnings",
"plugin:unicorn/recommended",
"xo",
"xo/browser"
],
"rules": {
"arrow-body-style": "off",
"capitalized-comments": "off",
"comma-dangle": [
"error",
"never"
],
"import/extensions": [
"error",
"ignorePackages",
{
"js": "always"
}
],
"import/first": "error",
"import/newline-after-import": "error",
"import/no-absolute-path": "error",
"import/no-amd": "error",
"import/no-cycle": [
"error",
{
"ignoreExternal": true
}
],
"import/no-duplicates": "error",
"import/no-extraneous-dependencies": "error",
"import/no-mutable-exports": "error",
"import/no-named-as-default": "error",
"import/no-named-as-default-member": "error",
"import/no-named-default": "error",
"import/no-self-import": "error",
"import/no-unassigned-import": [
"error"
],
"import/no-useless-path-segments": "error",
"import/order": "error",
"indent": [
"error",
2,
{
"MemberExpression": "off",
"SwitchCase": 1
}
],
"logical-assignment-operators": "off",
"max-params": [
"warn",
5
],
"multiline-ternary": [
"error",
"always-multiline"
],
"new-cap": [
"error",
{
"properties": false
}
],
"no-console": "error",
"no-negated-condition": "off",
"object-curly-spacing": [
"error",
"always"
],
"operator-linebreak": [
"error",
"after"
],
"prefer-object-has-own": "off",
"prefer-template": "error",
"semi": [
"error",
"never"
],
"strict": "error",
"unicorn/explicit-length-check": "off",
"unicorn/filename-case": "off",
"unicorn/no-anonymous-default-export": "off",
"unicorn/no-array-callback-reference": "off",
"unicorn/no-array-method-this-argument": "off",
"unicorn/no-null": "off",
"unicorn/no-typeof-undefined": "off",
"unicorn/no-unused-properties": "error",
"unicorn/numeric-separators-style": "off",
"unicorn/prefer-array-flat": "off",
"unicorn/prefer-at": "off",
"unicorn/prefer-dom-node-dataset": "off",
"unicorn/prefer-module": "off",
"unicorn/prefer-query-selector": "off",
"unicorn/prefer-spread": "off",
"unicorn/prefer-string-raw": "off",
"unicorn/prefer-string-replace-all": "off",
"unicorn/prefer-structured-clone": "off",
"unicorn/prevent-abbreviations": "off"
},
"overrides": [
{
"files": [
"build/**"
],
"env": {
"browser": false,
"node": true
},
"parserOptions": {
"sourceType": "module"
},
"rules": {
"no-console": "off",
"unicorn/prefer-top-level-await": "off"
}
},
{
"files": [
"js/**"
],
"parserOptions": {
"sourceType": "module"
}
},
{
"files": [
"js/tests/*.js",
"js/tests/integration/rollup*.js"
],
"env": {
"node": true
},
"parserOptions": {
"sourceType": "script"
}
},
{
"files": [
"js/tests/unit/**"
],
"env": {
"jasmine": true
},
"rules": {
"no-console": "off",
"unicorn/consistent-function-scoping": "off",
"unicorn/no-useless-undefined": "off",
"unicorn/prefer-add-event-listener": "off"
}
},
{
"files": [
"js/tests/visual/**"
],
"plugins": [
"html"
],
"settings": {
"html/html-extensions": [
".html"
]
},
"rules": {
"no-console": "off",
"no-new": "off",
"unicorn/no-array-for-each": "off"
}
},
{
"files": [
"scss/tests/**"
],
"env": {
"node": true
},
"parserOptions": {
"sourceType": "script"
}
},
{
"files": [
"site/**"
],
"env": {
"browser": true,
"node": false
},
"parserOptions": {
"sourceType": "script",
"ecmaVersion": 2019
},
"rules": {
"no-new": "off",
"unicorn/no-array-for-each": "off"
}
},
{
"files": [
"site/src/assets/application.js",
"site/src/assets/partials/*.js",
"site/src/assets/search.js",
"site/src/assets/snippets.js",
"site/src/assets/stackblitz.js",
"site/src/plugins/*.js"
],
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 2020
}
},
{
"files": [
"**/*.md"
],
"plugins": [
"markdown"
],
"processor": "markdown/markdown"
},
{
"files": [
"**/*.md/*.js",
"**/*.md/*.mjs"
],
"extends": "plugin:markdown/recommended-legacy",
"parserOptions": {
"sourceType": "module"
},
"rules": {
"unicorn/prefer-node-protocol": "off"
}
}
]
}

View File

@ -0,0 +1,8 @@
# Enforce Unix newlines
* text=auto eol=lf
# Don't diff or textually merge source maps
*.map binary
bootstrap.css linguist-vendored=false
bootstrap.js linguist-vendored=false

View File

@ -0,0 +1,3 @@
*.js @twbs/js-review
*.css @twbs/css-review
*.scss @twbs/css-review

View File

@ -0,0 +1,258 @@
# Contributing to Bootstrap
Looking to contribute something to Bootstrap? **Heres how you can help.**
Please take a moment to review this document in order to make the contribution
process easy and effective for everyone involved.
Following these guidelines helps to communicate that you respect the time of
the developers managing and developing this open source project. In return,
they should reciprocate that respect in addressing your issue or assessing
patches and features.
## Using the issue tracker
The [issue tracker](https://github.com/twbs/bootstrap/issues) is
the preferred channel for [bug reports](#bug-reports), [features requests](#feature-requests)
and [submitting pull requests](#pull-requests), but please respect the following
restrictions:
- Please **do not** use the issue tracker for personal support requests. Stack Overflow ([`bootstrap-5`](https://stackoverflow.com/questions/tagged/bootstrap-5) tag), [our GitHub Discussions](https://github.com/twbs/bootstrap/discussions) or [IRC](/README.md#community) are better places to get help.
- Please **do not** derail or troll issues. Keep the discussion on topic and
respect the opinions of others.
- Please **do not** post comments consisting solely of "+1" or ":thumbsup:".
Use [GitHub's "reactions" feature](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/)
instead. We reserve the right to delete comments which violate this rule.
- Please **do not** open issues regarding the official themes offered on <https://themes.getbootstrap.com/>.
Instead, please email any questions or feedback regarding those themes to `themes AT getbootstrap DOT com`.
## Issues assignment
The core team will be looking at the open issues, analyze them, and provide guidance on how to proceed. **Issues wont be assigned to anyone outside the core team.** However, contributors are welcome to participate in the discussion and provide their input on how to best solve the issue, and even submit a PR if they want to. Please wait that the issue is ready to be worked on before submitting a PR, we dont want to waste your time.
Please keep in mind that the core team is small, has limited resources and that we are not always able to respond immediately. We will try to provide feedback as soon as possible, but please be patient. If you dont get a response immediately, it doesnt mean that we are ignoring you or that we dont care about your issue or PR. We will get back to you as soon as we can.
## Issues and labels
Our bug tracker utilizes several labels to help organize and identify issues. Heres what they represent and how we use them:
- `browser bug` - Issues that are reported to us, but actually are the result of a browser-specific bug. These are diagnosed with reduced test cases and result in an issue opened on that browser's own bug tracker.
- `confirmed` - Issues that have been confirmed with a reduced test case and identify a bug in Bootstrap.
- `css` - Issues stemming from our compiled CSS or source Sass files.
- `docs` - Issues for improving or updating our documentation.
- `examples` - Issues involving the example templates included in our docs.
- `feature` - Issues asking for a new feature to be added, or an existing one to be extended or modified. New features require a minor version bump (e.g., `v3.0.0` to `v3.1.0`).
- `build` - Issues with our build system, which is used to run all our tests, concatenate and compile source files, and more.
- `help wanted` - Issues we need or would love help from the community to resolve.
- `js` - Issues stemming from our compiled or source JavaScript files.
- `meta` - Issues with the project itself or our GitHub repository.
For a complete look at our labels, see the [project labels page](https://github.com/twbs/bootstrap/labels).
## Bug reports
A bug is a _demonstrable problem_ that is caused by the code in the repository.
Good bug reports are extremely helpful, so thanks!
Guidelines for bug reports:
0. **[Validate your HTML](https://html5.validator.nu/)** to ensure your
problem isnt caused by a simple error in your own code.
1. **Use the GitHub issue search** &mdash; check if the issue has already been
reported.
2. **Check if the issue has been fixed** &mdash; try to reproduce it using the
latest `main` (or `v4-dev` branch if the issue is about v4) in the repository.
3. **Isolate the problem** &mdash; ideally create a [reduced test
case](https://css-tricks.com/reduced-test-cases/) and a live example.
These [v4 CodePen](https://codepen.io/team/bootstrap/pen/yLabNQL) and [v5 CodePen](https://codepen.io/team/bootstrap/pen/qBamdLj) are helpful templates.
A good bug report shouldnt leave others needing to chase you up for more
information. Please try to be as detailed as possible in your report. What is
your environment? What steps will reproduce the issue? What browser(s) and OS
experience the problem? Do other browsers show the bug differently? What
would you expect to be the outcome? All these details will help people to fix
any potential bugs.
Example:
> Short and descriptive example bug report title
>
> A summary of the issue and the browser/OS environment in which it occurs. If
> suitable, include the steps required to reproduce the bug.
>
> 1. This is the first step
> 2. This is the second step
> 3. Further steps, etc.
>
> `<url>` - a link to the reduced test case
>
> Any other information you want to share that is relevant to the issue being
> reported. This might include the lines of code that you have identified as
> causing the bug, and potential solutions (and your opinions on their
> merits).
### Reporting upstream browser bugs
Sometimes bugs reported to us are actually caused by bugs in the browser(s) themselves, not bugs in Bootstrap per se.
| Vendor(s) | Browser(s) | Rendering engine | Bug reporting website(s) | Notes |
| ------------- | ---------------------------- | ---------------- | ------------------------------------------------------ | -------------------------------------------------------- |
| Mozilla | Firefox | Gecko | <https://bugzilla.mozilla.org/enter_bug.cgi> | "Core" is normally the right product option to choose. |
| Apple | Safari | WebKit | <https://bugs.webkit.org/enter_bug.cgi?product=WebKit> | In Apples bug reporter, choose "Safari" as the product. |
| Google, Opera | Chrome, Chromium, Opera v15+ | Blink | <https://bugs.chromium.org/p/chromium/issues/list> | Click the "New issue" button. |
| Microsoft | Edge | Blink | <https://developer.microsoft.com/en-us/microsoft-edge/> | Go to "Help > Send Feedback" from the browser |
## Feature requests
Feature requests are welcome. But take a moment to find out whether your idea
fits with the scope and aims of the project. Its up to _you_ to make a strong
case to convince the projects developers of the merits of this feature. Please
provide as much detail and context as possible.
## Pull requests
Good pull requests—patches, improvements, new features—are a fantastic
help. They should remain focused in scope and avoid containing unrelated
commits.
**Please ask first** before embarking on any **significant** pull request (e.g.
implementing features, refactoring code, porting to a different language),
otherwise you risk spending a lot of time working on something that the
projects developers might not want to merge into the project. For trivial
things, or things that dont require a lot of your time, you can go ahead and
make a PR.
Please adhere to the [coding guidelines](#code-guidelines) used throughout the
project (indentation, accurate comments, etc.) and any other requirements
(such as test coverage).
**Do not edit `bootstrap.css` or `bootstrap.js`, and do not commit
any dist files (`dist/` or `js/dist`).** Those files are automatically generated by our build tools. You should
edit the source files in [`/bootstrap/scss/`](https://github.com/twbs/bootstrap/tree/main/scss)
and/or [`/bootstrap/js/src/`](https://github.com/twbs/bootstrap/tree/main/js/src) instead.
Similarly, when contributing to Bootstraps documentation, you should edit the
documentation source files in
[the `/bootstrap/site/content/docs/` directory of the `main` branch](https://github.com/twbs/bootstrap/tree/main/site/content/docs).
**Do not edit the `gh-pages` branch.** That branch is generated from the
documentation source files and is managed separately by the Bootstrap Core Team.
Adhering to the following process is the best way to get your work
included in the project:
1. [Fork](https://help.github.com/articles/fork-a-repo/) the project, clone your fork,
and configure the remotes:
```bash
# Clone your fork of the repo into the current directory
git clone https://github.com/<your-username>/bootstrap.git
# Navigate to the newly cloned directory
cd bootstrap
# Assign the original repo to a remote called "upstream"
git remote add upstream https://github.com/twbs/bootstrap.git
```
2. If you cloned a while ago, get the latest changes from upstream:
```bash
git checkout main
git pull upstream main
```
3. Install or update project dependencies with npm:
```bash
npm install
```
4. Create a new topic branch (off the main project development branch) to
contain your feature, change, or fix:
```bash
git checkout -b <topic-branch-name>
```
5. Commit your changes in logical chunks. Please adhere to these [git commit
message guidelines](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
or your code is unlikely be merged into the main project. Use Gits
[interactive rebase](https://help.github.com/articles/about-git-rebase/)
feature to tidy up your commits before making them public.
6. Ensure your changes compile the dist CSS and JS files in the `dist/` directory. Verify
the build succeeds locally without errors.
```bash
npm run dist
```
7. Locally merge (or rebase) the upstream development branch into your topic branch:
```bash
git pull [--rebase] upstream main
```
8. Commit your changes, but **do not push compiled CSS and JS files in `dist` and `js/dist`**.
Push your topic branch up to your fork:
```bash
git push origin <topic-branch-name>
```
9. [Open a pull request](https://help.github.com/articles/about-pull-requests/)
with a clear title and description against the `main` branch.
**IMPORTANT**: By submitting a patch, you agree to allow the project owners to
license your work under the terms of the [MIT License](../LICENSE) (if it
includes code changes) and under the terms of the
[Creative Commons Attribution 3.0 Unported License](https://creativecommons.org/licenses/by/3.0/)
(if it includes documentation changes).
## Code guidelines
### HTML
[Adhere to the Code Guide.](https://codeguide.co/#html)
- Use tags and elements appropriate for an HTML5 doctype (e.g., self-closing tags).
- Use CDNs and HTTPS for third-party JS when possible. We dont use protocol-relative URLs in this case because they break when viewing the page locally via `file://`.
- Use [WAI-ARIA](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA) attributes in documentation examples to promote accessibility.
### CSS
[Adhere to the Code Guide.](https://codeguide.co/#css)
- When feasible, default color palettes should comply with [WCAG color contrast guidelines](https://www.w3.org/TR/WCAG/#distinguishable).
- Except in rare cases, dont remove default `:focus` styles (via e.g. `outline: none;`) without providing alternative styles. See [this A11Y Project post](https://www.a11yproject.com/posts/2013-01-25-never-remove-css-outlines/) for more details.
### JS
- No semicolons (in client-side JS)
- 2 spaces (no tabs)
- strict mode
- "Attractive"
### Checking coding style
Run `npm run test` before committing to ensure your changes follow our coding standards.
## License
By contributing your code, you agree to license your contribution under the [MIT License](../LICENSE).
By contributing to the documentation, you agree to license your contribution under the [Creative Commons Attribution 3.0 Unported License](https://creativecommons.org/licenses/by/3.0/).
Prior to v3.1.0, Bootstraps code was released under the Apache License v2.0.

View File

@ -0,0 +1,62 @@
name: Report a bug
description: Tell us about a bug or issue you may have identified in Bootstrap.
title: "Provide a general summary of the issue"
labels: [bug]
assignees: "-"
body:
- type: checkboxes
attributes:
label: Prerequisites
description: Take a couple minutes to help our maintainers work faster.
options:
- label: I have [searched](https://github.com/twbs/bootstrap/issues?utf8=%E2%9C%93&q=is%3Aissue) for duplicate or closed issues
required: true
- label: I have [validated](https://html5.validator.nu/) any HTML to avoid common problems
required: true
- label: I have read the [contributing guidelines](https://github.com/twbs/bootstrap/blob/main/.github/CONTRIBUTING.md)
required: true
- type: textarea
id: what-happened
attributes:
label: Describe the issue
description: Provide a summary of the issue and what you expected to happen, including specific steps to reproduce.
validations:
required: true
- type: textarea
id: reduced-test-case
attributes:
label: Reduced test cases
description: Include links [reduced test case](https://css-tricks.com/reduced-test-cases/) links or suggested fixes using CodePen ([v4 template](https://codepen.io/team/bootstrap/pen/yLabNQL) or [v5 template](https://codepen.io/team/bootstrap/pen/qBamdLj)).
validations:
required: true
- type: dropdown
id: os
attributes:
label: What operating system(s) are you seeing the problem on?
multiple: true
options:
- Windows
- macOS
- Android
- iOS
- Linux
validations:
required: true
- type: dropdown
id: browser
attributes:
label: What browser(s) are you seeing the problem on?
multiple: true
options:
- Chrome
- Safari
- Firefox
- Microsoft Edge
- Opera
- type: input
id: version
attributes:
label: What version of Bootstrap are you using?
placeholder: "e.g., v5.1.0 or v4.5.2"
validations:
required: true

View File

@ -0,0 +1,4 @@
contact_links:
- name: Ask the community
url: https://github.com/twbs/bootstrap/discussions/new
about: Ask and discuss questions with other Bootstrap community members.

View File

@ -0,0 +1,29 @@
name: Feature request
description: Suggest new or updated features to include in Bootstrap.
title: "Suggest a new feature"
labels: [feature]
assignees: []
body:
- type: checkboxes
attributes:
label: Prerequisites
description: Take a couple minutes to help our maintainers work faster.
options:
- label: I have [searched](https://github.com/twbs/bootstrap/issues?utf8=%E2%9C%93&q=is%3Aissue) for duplicate or closed feature requests
required: true
- label: I have read the [contributing guidelines](https://github.com/twbs/bootstrap/blob/main/.github/CONTRIBUTING.md)
required: true
- type: textarea
id: proposal
attributes:
label: Proposal
description: Provide detailed information for what we should add, including relevant links to prior art, screenshots, or live demos whenever possible.
validations:
required: true
- type: textarea
id: motivation
attributes:
label: Motivation and context
description: Tell us why this change is needed or helpful, and what problems it may help solve.
validations:
required: true

View File

@ -0,0 +1,38 @@
### Description
<!-- Describe your changes in detail -->
### Motivation & Context
<!-- Why is this change required? What problem does it solve? -->
### Type of changes
<!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply. -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Refactoring (non-breaking change)
- [ ] Breaking change (fix or feature that would change existing functionality)
### Checklist
<!-- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!-- If youre unsure about any of these, dont hesitate to ask. Were here to help! -->
- [ ] I have read the [contributing guidelines](https://github.com/twbs/bootstrap/blob/main/.github/CONTRIBUTING.md)
- [ ] My code follows the code style of the project _(using `npm run lint`)_
- [ ] My change introduces changes to the documentation
- [ ] I have updated the documentation accordingly
- [ ] I have added tests to cover my changes
- [ ] All new and existing tests passed
#### Live previews
<!-- Please add direct links where your modifications can be seen in the documentation -->
- <https://deploy-preview-{your_pr_number}--twbs-bootstrap.netlify.app/>
### Related issues
<!-- Please link any related issues here. -->

View File

@ -0,0 +1,11 @@
### Bug reports
See the [contributing guidelines](CONTRIBUTING.md) for sharing bug reports.
### How-to
For general troubleshooting or help getting started:
- Ask and explore [our GitHub Discussions](https://github.com/twbs/bootstrap/discussions).
- Chat with fellow Bootstrappers in IRC. On the `irc.libera.chat` server, in the `#bootstrap` channel.
- Ask and explore Stack Overflow with the [`bootstrap-5`](https://stackoverflow.com/questions/tagged/bootstrap-5) tag.

View File

@ -0,0 +1,3 @@
name: "CodeQL config"
paths-ignore:
- dist

View File

@ -0,0 +1,26 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: weekly
day: tuesday
time: "12:00"
timezone: Europe/Athens
- package-ecosystem: npm
directory: "/"
labels:
- dependencies
- v5
schedule:
interval: weekly
day: tuesday
time: "12:00"
timezone: Europe/Athens
versioning-strategy: increase
rebase-strategy: disabled
groups:
production-dependencies:
dependency-type: "production"
development-dependencies:
dependency-type: "development"

View File

@ -0,0 +1,60 @@
name-template: 'v$NEXT_MAJOR_VERSION'
tag-template: 'v$NEXT_MAJOR_VERSION'
prerelease: true
exclude-labels:
- 'skip-changelog'
categories:
- title: '❗ Breaking Changes'
labels:
- 'breaking-change'
- title: '🚀 Highlights'
labels:
- 'release-highlight'
- title: '🚀 Features'
labels:
- 'new-feature'
- 'feature'
- 'enhancement'
- title: '🐛 Bug fixes'
labels:
- 'fix'
- 'bugfix'
- 'bug'
- title: '⚡ Performance improvements'
labels:
- 'performance'
- title: '🎨 CSS'
labels:
- 'css'
- title: '☕️ JavaScript'
labels:
- 'js'
- title: '📖 Docs'
labels:
- 'docs'
- title: '🛠 Examples'
labels:
- 'examples'
- title: '🌎 Accessibility'
labels:
- 'accessibility'
- title: '🔧 Utility API'
labels:
- 'utility API'
- 'utilities'
- title: '🏭 Tests'
labels:
- 'tests'
- title: '🧰 Misc'
labels:
- 'build'
- 'meta'
- 'chore'
- 'CI'
- title: '📦 Dependencies'
labels:
- 'dependencies'
change-template: '- #$NUMBER: $TITLE'
template: |
## Changes
$CHANGES

Some files were not shown because too many files have changed in this diff Show More