full flow with overlays
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Michele Scandura 2021-09-17 10:53:03 +01:00
parent d0663e1471
commit 9abe30904f
16 changed files with 564 additions and 26 deletions

View File

@ -7,6 +7,7 @@ namespace Sledgemapper.Api.Commands
{
public double Timestamp { get; private set; }
public string SessionName { get; private set; }
public Guid SessionId { get; private set; }
public Guid Campaign { get; private set; }
public string UserId { get; private set; }
@ -25,10 +26,10 @@ namespace Sledgemapper.Api.Commands
UserId = userId;
}
public BaseCommand(Guid campaign, string sessionName, string userId)
public BaseCommand(Guid campaign, Guid sessionId, string userId)
{
Timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds();
SessionName = sessionName;
SessionId = sessionId;
Campaign = campaign;
UserId = userId;
}

View File

@ -7,7 +7,7 @@ namespace Sledgemapper.Api.Commands
{
public Overlay Overlay { get; private set; }
public NewOverlayCommand(Guid campaignId, string mapId, Overlay overlay, string userId) : base(campaignId, mapId, userId)
public NewOverlayCommand(Guid campaignId, Guid mapId, Overlay overlay, string userId) : base(campaignId, mapId, userId)
{
Overlay = overlay;
}

View File

@ -1,6 +1,8 @@
using System;
namespace Sledgemapper.Api.Commands
{
public class NewSessionCommand : BaseCommand<bool>
public class NewSessionCommand : BaseCommand<Guid>
{
public NewSessionCommand(string campaign, string sessionName, string userId) : base(campaign, sessionName, userId)
{

View File

@ -19,7 +19,7 @@ namespace Sledgemapper.Api.Controllers
public MapController(IMediator mediator) => _mediator = mediator;
[HttpPost]
public async Task<bool> Post(string campaign, string mapName)
public async Task<Guid> Post(string campaign, string mapName)
{
var result = await _mediator.Send(new NewSessionCommand(campaign, mapName, UserId));
return result;
@ -39,7 +39,7 @@ namespace Sledgemapper.Api.Controllers
}
[HttpPost("overlay")]
public async Task Post(Guid campaign, string mapName, [FromBody] Overlay overlay)
public async Task Post(Guid campaign, Guid mapName, [FromBody] Overlay overlay)
{
await _mediator.Send(new NewOverlayCommand(campaign, mapName, overlay, UserId));
}

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
using Sledgemapper.Api.Models;
using Sledgemapper.Entities;
@ -8,8 +9,10 @@ namespace Sledgemapper.Api.Core.Entities
{
[Index(nameof(CampaignName), nameof(OwnerId), IsUnique = true)]
public class Campaign
{
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid CampaignId { get; set; }
public string CampaignName { get; set; }
public string OwnerId { get; set; }

View File

@ -1,12 +1,14 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Sledgemapper.Api.Models
{
[Index(nameof(CampaignId), nameof(SessionName), IsUnique = true)]
public class Session
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid SessionId { get; set; }

View File

@ -27,7 +27,7 @@ namespace Sledgemapper.Api.Handlers
var campaign = await _dbcontext.Campaigns.Where(campaign => campaign.CampaignId == command.Campaign && campaign.OwnerId == command.UserId).Include(campaign => campaign.Maps).FirstAsync();
var maps = campaign.Maps.Any(s => s.SessionId == new Guid(command.SessionName));
var maps = campaign.Maps.Any(s => s.SessionId == command.SessionId);
if (!maps)
{
@ -35,7 +35,7 @@ namespace Sledgemapper.Api.Handlers
}
var jsonString = JsonSerializer.Serialize(command.Overlay);
var session = _dbcontext.Sessions.First(m => m.SessionId == new Guid(command.SessionName));
var session = _dbcontext.Sessions.First(m => m.SessionId == command.SessionId);
_dbcontext.MapLogs.Add(new Models.MapLog
{
Operation = "N",

View File

@ -2,13 +2,14 @@ using MediatR;
using Sledgemapper.Api.Commands;
using Sledgemapper.Api.Infrastructure.Data;
using Sledgemapper.Api.Models;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Sledgemapper.Api.Handlers
{
public class StartNewSessionHandler : IRequestHandler<NewSessionCommand, bool>
public class StartNewSessionHandler : IRequestHandler<NewSessionCommand, Guid>
{
private readonly IMediator _mediator;
private readonly SledgemapperDbContext _dbcontext;
@ -19,19 +20,20 @@ namespace Sledgemapper.Api.Handlers
_dbcontext = dbcontext;
}
public async Task<bool> Handle(NewSessionCommand notification, CancellationToken cancellationToken)
public async Task<Guid> Handle(NewSessionCommand notification, CancellationToken cancellationToken)
{
var campaign = _dbcontext.Campaigns.First(c => c.CampaignId == notification.Campaign && c.OwnerId == notification.UserId.ToString());
_dbcontext.Sessions.Add(new Session
var session = new Session
{
SessionName = notification.SessionName,
OwnerUserId = notification.UserId,
CampaignId = campaign.CampaignId
});
};
_dbcontext.Sessions.Add(session);
await _dbcontext.SaveChangesAsync();
return true;
return session.SessionId;
}
}
}

View File

@ -0,0 +1,508 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Sledgemapper.Api.Infrastructure.Data;
namespace Sledgemapper.Api.Migrations
{
[DbContext(typeof(SledgemapperDbContext))]
[Migration("20210917091001_SessionIdToGuidAuto")]
partial class SessionIdToGuidAuto
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "5.0.6");
modelBuilder.Entity("CampaignUser", b =>
{
b.Property<Guid>("CampaignsCampaignId")
.HasColumnType("TEXT");
b.Property<string>("InvitedUsersId")
.HasColumnType("TEXT");
b.HasKey("CampaignsCampaignId", "InvitedUsersId");
b.HasIndex("InvitedUsersId");
b.ToTable("CampaignUser");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<int>("AccessFailedCount")
.HasColumnType("INTEGER");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<bool>("EmailConfirmed")
.HasColumnType("INTEGER");
b.Property<bool>("LockoutEnabled")
.HasColumnType("INTEGER");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("TEXT");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("PasswordHash")
.HasColumnType("TEXT");
b.Property<string>("PhoneNumber")
.HasColumnType("TEXT");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("INTEGER");
b.Property<string>("SecurityStamp")
.HasColumnType("TEXT");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("INTEGER");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("ProviderKey")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("ProviderDisplayName")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.HasColumnType("TEXT");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Campaign", b =>
{
b.Property<Guid>("CampaignId")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<string>("CampaignName")
.HasColumnType("TEXT");
b.Property<string>("OwnerId")
.HasColumnType("TEXT");
b.HasKey("CampaignId");
b.HasIndex("OwnerId");
b.HasIndex("CampaignName", "OwnerId")
.IsUnique();
b.ToTable("Campaigns");
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Map", b =>
{
b.Property<int>("MapId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("CampaignId")
.HasColumnType("INTEGER");
b.Property<string>("MapName")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("MapId");
b.ToTable("Maps");
});
modelBuilder.Entity("Sledgemapper.Api.Models.MapLog", b =>
{
b.Property<int>("MapLogId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Object")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("Operation")
.IsRequired()
.HasMaxLength(1)
.HasColumnType("TEXT");
b.Property<Guid>("SessionId")
.HasColumnType("TEXT");
b.Property<double>("Timestamp")
.HasColumnType("REAL");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("MapLogId");
b.ToTable("MapLogs");
});
modelBuilder.Entity("Sledgemapper.Api.Models.Session", b =>
{
b.Property<Guid>("SessionId")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("CampaignId")
.HasColumnType("TEXT");
b.Property<string>("OwnerUserId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("SessionName")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("SessionId");
b.HasIndex("CampaignId", "SessionName")
.IsUnique();
b.ToTable("Sessions");
});
modelBuilder.Entity("Sledgemapper.Api.Models.SessionUser", b =>
{
b.Property<int>("SessionUserId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<Guid>("SessionId")
.HasColumnType("TEXT");
b.Property<int>("UserId")
.HasColumnType("INTEGER");
b.HasKey("SessionUserId");
b.ToTable("SessionUsers");
});
modelBuilder.Entity("Sledgemapper.Api.Models.Snapshot", b =>
{
b.Property<int>("SnapshotId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Object")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("SessionId")
.HasColumnType("TEXT");
b.Property<double>("Timestamp")
.HasColumnType("REAL");
b.HasKey("SnapshotId");
b.ToTable("Snapshots");
});
modelBuilder.Entity("Sledgemapper.Api.Models.UserConnection", b =>
{
b.Property<int>("UserConnectionId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ConnectionId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("UserId")
.HasColumnType("INTEGER");
b.HasKey("UserConnectionId");
b.ToTable("UserConnections");
});
modelBuilder.Entity("Sledgemapper.Entities.User", b =>
{
b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser");
b.Property<string>("FirstName")
.HasColumnType("TEXT");
b.Property<string>("Initials")
.HasColumnType("TEXT");
b.Property<string>("LastName")
.HasColumnType("TEXT");
b.Property<byte[]>("PasswordSalt")
.HasColumnType("BLOB");
b.ToTable("Users");
});
modelBuilder.Entity("CampaignUser", b =>
{
b.HasOne("Sledgemapper.Api.Core.Entities.Campaign", null)
.WithMany()
.HasForeignKey("CampaignsCampaignId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Sledgemapper.Entities.User", null)
.WithMany()
.HasForeignKey("InvitedUsersId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Campaign", b =>
{
b.HasOne("Sledgemapper.Entities.User", "Owner")
.WithMany()
.HasForeignKey("OwnerId");
b.Navigation("Owner");
});
modelBuilder.Entity("Sledgemapper.Api.Models.Session", b =>
{
b.HasOne("Sledgemapper.Api.Core.Entities.Campaign", null)
.WithMany("Maps")
.HasForeignKey("CampaignId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Sledgemapper.Entities.User", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithOne()
.HasForeignKey("Sledgemapper.Entities.User", "Id")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Sledgemapper.Api.Core.Entities.Campaign", b =>
{
b.Navigation("Maps");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,17 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Sledgemapper.Api.Migrations
{
public partial class SessionIdToGuidAuto : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

View File

@ -22,7 +22,7 @@ namespace Sledgemapper.Clients
Task RefreshPlayers();
Task NewLine(Line line);
Task Ping(Ping ping);
Task NewCampaign(string campaignName);
Task<List<Campaign>> GetCampaigns();
//Task NewCampaign(string campaignName);
//Task<List<Campaign>> GetCampaigns();
}
}

View File

@ -199,7 +199,7 @@ namespace Sledgemapper
Queue.Enqueue(async () => await Execute(async () => await Api.NewTile(tile, SessionData.SessionName).ConfigureAwait(false)));
break;
case Overlay overlay:
Queue.Enqueue(async () => await Execute(async () => await Api.NewOverlay(overlay,State.Instance.CampaignId.ToString(), State.Instance.MapId.ToString()).ConfigureAwait(false)));
Queue.Enqueue(async () => await Execute(async () => await Api.NewOverlay(overlay,State.Instance.CampaignId, State.Instance.MapId).ConfigureAwait(false)));
break;
case Wall wall:
Queue.Enqueue(async () => await Execute(async () => await Api.NewWall(wall, SessionData.SessionName).ConfigureAwait(false)));

View File

@ -12,8 +12,8 @@ namespace Sledgemapper
[Get("/session/{sessionName}")]
Task<Session> Session(string sessionName);
[Post("/map/{campaignName}/{sessionName}")]
Task<bool> NewSession(Guid campaignid, string sessionName);
[Post("/map/{campaignid}/{sessionName}")]
Task<Guid> NewSession(Guid campaignid, string sessionName);
[Post("/session/{sessionName}/snapshot")]
Task SaveSnapshot([Body] Session session, string sessionName);
@ -22,7 +22,7 @@ namespace Sledgemapper
Task NewTile([Body] Tile tile, string sessionName);
[Post("/map/{campaignId}/{mapId}/overlay")]
Task NewOverlay([Body] Overlay overlay, string campaignId, string mapId);
Task NewOverlay([Body] Overlay overlay, Guid campaignId, Guid mapId);
[Post("/session/{sessionName}/note")]
Task NewNote([Body] Note note, string sessionName);

View File

@ -26,7 +26,7 @@ namespace Sledgemapper
public string CampaignName { get; set; }
public Guid CampaignId { get; internal set; }
public string MapName { get; internal set; }
public int MapId { get; internal set; }
public Guid MapId { get; internal set; }
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
@ -57,6 +57,8 @@ namespace Sledgemapper
}
}
public Guid SessionId { get; internal set; }
public void SelectClosestWall(Point mousePosition)
{
var topLeft = new Point(HoveredTile.X * TileSize, HoveredTile.Y * TileSize);

View File

@ -15,7 +15,7 @@ namespace Sledgemapper.UI
private TinyMessengerHub Messenger { get; }
private string _selectedMap;
private int _selectedMapId;
private Guid _selectedMapId;
public MapList(CommunicationManager communicationManager, TinyMessengerHub messenger)
{
CommunicationManager = communicationManager;
@ -66,7 +66,7 @@ namespace Sledgemapper.UI
}
item.Background = new SolidBrush(Settings.Instance.OverlayTintColor);
_selectedMap = item.ItemName.Text;
_selectedMapId = (int)item.Tag;
_selectedMapId = (Guid)item.Tag;
}
private void OnMenuMapNew(object sender, EventArgs e)

View File

@ -42,14 +42,15 @@ namespace Sledgemapper.UI
var successful = false;
try
{
var result = await CommunicationManager.Api.NewSession(State.Instance.CampaignName, localContent.Content.TxtSession.Text);
var sessionGuid = await CommunicationManager.Api.NewSession(State.Instance.CampaignId, localContent.Content.TxtSession.Text);
if (result)
if (sessionGuid != Guid.Empty)
{
CommunicationManager.SessionData.SessionName = localContent.Content.TxtSession.Text;
State.Instance.SessionId = sessionGuid;
}
successful = result;
successful = true;
var result2 = await CommunicationManager.Connection?.InvokeAsync<Session>("JoinSession", localContent.Content.TxtSession.Text);
CommunicationManager.SessionData.SessionId = result2.SessionId;
CommunicationManager.SessionData.SessionName = localContent.Content.TxtSession.Text;