✨ Sharable thought
This commit is contained in:
163
DysonNetwork.Insight/Migrations/20251116123552_SharableThought.Designer.cs
generated
Normal file
163
DysonNetwork.Insight/Migrations/20251116123552_SharableThought.Designer.cs
generated
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using DysonNetwork.Insight;
|
||||||
|
using DysonNetwork.Shared.Models;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using NodaTime;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace DysonNetwork.Insight.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(AppDatabase))]
|
||||||
|
[Migration("20251116123552_SharableThought")]
|
||||||
|
partial class SharableThought
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "9.0.11")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Shared.Models.SnThinkingSequence", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<Guid>("AccountId")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("account_id");
|
||||||
|
|
||||||
|
b.Property<Instant>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("created_at");
|
||||||
|
|
||||||
|
b.Property<Instant?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("deleted_at");
|
||||||
|
|
||||||
|
b.Property<bool>("IsPublic")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("is_public");
|
||||||
|
|
||||||
|
b.Property<long>("PaidToken")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("paid_token");
|
||||||
|
|
||||||
|
b.Property<string>("Topic")
|
||||||
|
.HasMaxLength(4096)
|
||||||
|
.HasColumnType("character varying(4096)")
|
||||||
|
.HasColumnName("topic");
|
||||||
|
|
||||||
|
b.Property<long>("TotalToken")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("total_token");
|
||||||
|
|
||||||
|
b.Property<Instant>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("updated_at");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_thinking_sequences");
|
||||||
|
|
||||||
|
b.ToTable("thinking_sequences", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Shared.Models.SnThinkingThought", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<Instant>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("created_at");
|
||||||
|
|
||||||
|
b.Property<Instant?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("deleted_at");
|
||||||
|
|
||||||
|
b.Property<List<SnCloudFileReferenceObject>>("Files")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasColumnName("files");
|
||||||
|
|
||||||
|
b.Property<string>("ModelName")
|
||||||
|
.HasMaxLength(4096)
|
||||||
|
.HasColumnType("character varying(4096)")
|
||||||
|
.HasColumnName("model_name");
|
||||||
|
|
||||||
|
b.Property<List<SnThinkingMessagePart>>("Parts")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasColumnName("parts");
|
||||||
|
|
||||||
|
b.Property<int>("Role")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("role");
|
||||||
|
|
||||||
|
b.Property<Guid>("SequenceId")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("sequence_id");
|
||||||
|
|
||||||
|
b.Property<long>("TokenCount")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("token_count");
|
||||||
|
|
||||||
|
b.Property<Instant>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("updated_at");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_thinking_thoughts");
|
||||||
|
|
||||||
|
b.HasIndex("SequenceId")
|
||||||
|
.HasDatabaseName("ix_thinking_thoughts_sequence_id");
|
||||||
|
|
||||||
|
b.ToTable("thinking_thoughts", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Shared.Models.SnUnpaidAccount", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("AccountId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("account_id");
|
||||||
|
|
||||||
|
b.Property<DateTime>("MarkedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("marked_at");
|
||||||
|
|
||||||
|
b.HasKey("AccountId")
|
||||||
|
.HasName("pk_unpaid_accounts");
|
||||||
|
|
||||||
|
b.ToTable("unpaid_accounts", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Shared.Models.SnThinkingThought", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("DysonNetwork.Shared.Models.SnThinkingSequence", "Sequence")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("SequenceId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_thinking_thoughts_thinking_sequences_sequence_id");
|
||||||
|
|
||||||
|
b.Navigation("Sequence");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace DysonNetwork.Insight.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class SharableThought : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "is_public",
|
||||||
|
table: "thinking_sequences",
|
||||||
|
type: "boolean",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "is_public",
|
||||||
|
table: "thinking_sequences");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,6 +44,10 @@ namespace DysonNetwork.Insight.Migrations
|
|||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("deleted_at");
|
.HasColumnName("deleted_at");
|
||||||
|
|
||||||
|
b.Property<bool>("IsPublic")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("is_public");
|
||||||
|
|
||||||
b.Property<long>("PaidToken")
|
b.Property<long>("PaidToken")
|
||||||
.HasColumnType("bigint")
|
.HasColumnType("bigint")
|
||||||
.HasColumnName("paid_token");
|
.HasColumnName("paid_token");
|
||||||
|
|||||||
@@ -22,11 +22,16 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service)
|
|||||||
[Required] public string UserMessage { get; set; } = null!;
|
[Required] public string UserMessage { get; set; } = null!;
|
||||||
public string? ServiceId { get; set; }
|
public string? ServiceId { get; set; }
|
||||||
public Guid? SequenceId { get; set; }
|
public Guid? SequenceId { get; set; }
|
||||||
public List<string>? AttachedPosts { get; set; }
|
public List<string>? AttachedPosts { get; set; } = [];
|
||||||
public List<Dictionary<string, dynamic>>? AttachedMessages { get; set; }
|
public List<Dictionary<string, dynamic>>? AttachedMessages { get; set; }
|
||||||
public List<string> AcceptProposals { get; set; } = [];
|
public List<string> AcceptProposals { get; set; } = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class UpdateSharingRequest
|
||||||
|
{
|
||||||
|
public bool IsPublic { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class ThoughtServiceInfo
|
public class ThoughtServiceInfo
|
||||||
{
|
{
|
||||||
public string ServiceId { get; set; } = null!;
|
public string ServiceId { get; set; } = null!;
|
||||||
@@ -76,7 +81,6 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service)
|
|||||||
return BadRequest("Service not found or configured.");
|
return BadRequest("Service not found or configured.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Check perk level from `currentUser`
|
|
||||||
if (serviceInfo.PerkLevel > 0 && !currentUser.IsSuperuser)
|
if (serviceInfo.PerkLevel > 0 && !currentUser.IsSuperuser)
|
||||||
if (currentUser.PerkSubscription is null ||
|
if (currentUser.PerkSubscription is null ||
|
||||||
PerkSubscriptionPrivilege.GetPrivilegeFromIdentifier(currentUser.PerkSubscription.Identifier) <
|
PerkSubscriptionPrivilege.GetPrivilegeFromIdentifier(currentUser.PerkSubscription.Identifier) <
|
||||||
@@ -407,6 +411,25 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service)
|
|||||||
return Ok(sequences);
|
return Ok(sequences);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPatch("sequences/{sequenceId:guid}/sharing")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||||
|
public async Task<ActionResult> UpdateSequenceSharing(Guid sequenceId, [FromBody] UpdateSharingRequest request)
|
||||||
|
{
|
||||||
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
var accountId = Guid.Parse(currentUser.Id);
|
||||||
|
|
||||||
|
var sequence = await service.GetSequenceAsync(sequenceId);
|
||||||
|
if (sequence == null) return NotFound();
|
||||||
|
if (sequence.AccountId != accountId) return Forbid();
|
||||||
|
|
||||||
|
sequence.IsPublic = request.IsPublic;
|
||||||
|
await service.UpdateSequenceAsync(sequence);
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the thoughts in a specific thinking sequence.
|
/// Retrieves the thoughts in a specific thinking sequence.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -419,12 +442,18 @@ public class ThoughtController(ThoughtProvider provider, ThoughtService service)
|
|||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult<List<SnThinkingThought>>> GetSequenceThoughts(Guid sequenceId)
|
public async Task<ActionResult<List<SnThinkingThought>>> GetSequenceThoughts(Guid sequenceId)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
var sequence = await service.GetSequenceAsync(sequenceId);
|
||||||
var accountId = Guid.Parse(currentUser.Id);
|
|
||||||
|
|
||||||
var sequence = await service.GetOrCreateSequenceAsync(accountId, sequenceId);
|
|
||||||
if (sequence == null) return NotFound();
|
if (sequence == null) return NotFound();
|
||||||
|
|
||||||
|
if (!sequence.IsPublic)
|
||||||
|
{
|
||||||
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
var accountId = Guid.Parse(currentUser.Id);
|
||||||
|
|
||||||
|
if (sequence.AccountId != accountId)
|
||||||
|
return StatusCode(403);
|
||||||
|
}
|
||||||
|
|
||||||
var thoughts = await service.GetPreviousThoughtsAsync(sequence);
|
var thoughts = await service.GetPreviousThoughtsAsync(sequence);
|
||||||
|
|
||||||
return Ok(thoughts);
|
return Ok(thoughts);
|
||||||
|
|||||||
@@ -36,6 +36,17 @@ public class ThoughtService(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<SnThinkingSequence?> GetSequenceAsync(Guid sequenceId)
|
||||||
|
{
|
||||||
|
return await db.ThinkingSequences.FindAsync(sequenceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateSequenceAsync(SnThinkingSequence sequence)
|
||||||
|
{
|
||||||
|
db.ThinkingSequences.Update(sequence);
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<SnThinkingThought> SaveThoughtAsync(
|
public async Task<SnThinkingThought> SaveThoughtAsync(
|
||||||
SnThinkingSequence sequence,
|
SnThinkingSequence sequence,
|
||||||
List<SnThinkingMessagePart> parts,
|
List<SnThinkingMessagePart> parts,
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ public class SnThinkingSequence : ModelBase
|
|||||||
public long TotalToken { get; set; }
|
public long TotalToken { get; set; }
|
||||||
public long PaidToken { get; set; }
|
public long PaidToken { get; set; }
|
||||||
|
|
||||||
|
public bool IsPublic { get; set; } = false;
|
||||||
|
|
||||||
public Guid AccountId { get; set; }
|
public Guid AccountId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user