@@ -18,27 +18,25 @@ You should have received a copy of the Affero GNU General Public License
1818*/
1919
2020using System ;
21- using System . Collections . Generic ;
2221using System . Linq ;
2322using System . Security . Claims ;
2423using System . Text . Json ;
2524using System . Threading . Tasks ;
2625using AngleSharp ;
27- using AngleSharp . Dom ;
2826using Microsoft . AspNetCore . Authorization ;
2927using Microsoft . AspNetCore . Http ;
3028using Microsoft . AspNetCore . Mvc ;
3129using Microsoft . Extensions . Logging ;
3230using MongoDB . Bson ;
3331using MongoDB . Driver ;
34- using Notesnook . API . Authorization ;
32+ using NanoidDotNet ;
33+ using Notesnook . API . Extensions ;
3534using Notesnook . API . Models ;
3635using Notesnook . API . Services ;
3736using Streetwriters . Common ;
3837using Streetwriters . Common . Helpers ;
3938using Streetwriters . Common . Interfaces ;
4039using Streetwriters . Common . Messages ;
41- using Streetwriters . Data . Interfaces ;
4240using Streetwriters . Data . Repositories ;
4341
4442namespace Notesnook . API . Controllers
@@ -95,6 +93,22 @@ private async Task<Monograph> FindMonographAsync(string itemId)
9593 return await result . FirstOrDefaultAsync ( ) ;
9694 }
9795
96+ private async Task < Monograph > FindMonographBySlugAsync ( string slug )
97+ {
98+ var result = await monographs . Collection . FindAsync (
99+ Builders < Monograph > . Filter . Eq ( "Slug" , slug ) ,
100+ new FindOptions < Monograph >
101+ {
102+ Limit = 1
103+ } ) ;
104+ return await result . FirstOrDefaultAsync ( ) ;
105+ }
106+
107+ private static string GenerateSlug ( )
108+ {
109+ return Nanoid . Generate ( size : 24 ) ;
110+ }
111+
98112 [ HttpPost ]
99113 public async Task < IActionResult > PublishAsync ( [ FromQuery ] string ? deviceId , [ FromBody ] Monograph monograph )
100114 {
@@ -120,6 +134,7 @@ public async Task<IActionResult> PublishAsync([FromQuery] string? deviceId, [Fro
120134 }
121135 monograph . Deleted = false ;
122136 monograph . ViewCount = 0 ;
137+ monograph . Slug = GenerateSlug ( ) ;
123138 await monographs . Collection . ReplaceOneAsync (
124139 CreateMonographFilter ( userId , monograph ) ,
125140 monograph ,
@@ -131,7 +146,8 @@ await monographs.Collection.ReplaceOneAsync(
131146 return Ok ( new
132147 {
133148 id = monograph . ItemId ,
134- datePublished = monograph . DatePublished
149+ datePublished = monograph . DatePublished ,
150+ publishUrl = monograph . ConstructPublishUrl ( )
135151 } ) ;
136152 }
137153 catch ( Exception e )
@@ -164,6 +180,7 @@ public async Task<IActionResult> UpdateAsync([FromQuery] string? deviceId, [From
164180 monograph . Content = null ;
165181
166182 monograph . DatePublished = DateTimeOffset . UtcNow . ToUnixTimeMilliseconds ( ) ;
183+ monograph . Slug = GenerateSlug ( ) ;
167184 var result = await monographs . Collection . UpdateOneAsync (
168185 CreateMonographFilter ( userId , monograph ) ,
169186 Builders < Monograph > . Update
@@ -172,6 +189,7 @@ public async Task<IActionResult> UpdateAsync([FromQuery] string? deviceId, [From
172189 . Set ( m => m . EncryptedContent , monograph . EncryptedContent )
173190 . Set ( m => m . SelfDestruct , monograph . SelfDestruct )
174191 . Set ( m => m . Title , monograph . Title )
192+ . Set ( m => m . Slug , monograph . Slug )
175193 . Set ( m => m . Password , monograph . Password )
176194 ) ;
177195 if ( ! result . IsAcknowledged ) return BadRequest ( ) ;
@@ -181,7 +199,8 @@ public async Task<IActionResult> UpdateAsync([FromQuery] string? deviceId, [From
181199 return Ok ( new
182200 {
183201 id = monograph . ItemId ,
184- datePublished = monograph . DatePublished
202+ datePublished = monograph . DatePublished ,
203+ publishUrl = monograph . ConstructPublishUrl ( )
185204 } ) ;
186205 }
187206 catch ( Exception e )
@@ -208,11 +227,25 @@ public async Task<IActionResult> GetUserMonographsAsync()
208227 return Ok ( userMonographs . Select ( ( m ) => m . ItemId ?? m . Id ) ) ;
209228 }
210229
211- [ HttpGet ( "{id }" ) ]
230+ [ HttpGet ( "{slugOrId }" ) ]
212231 [ AllowAnonymous ]
213- public async Task < IActionResult > GetMonographAsync ( [ FromRoute ] string id )
232+ public async Task < IActionResult > GetMonographAsync ( [ FromRoute ] string slugOrId )
214233 {
215- var monograph = await FindMonographAsync ( id ) ;
234+ var monograph = await FindMonographBySlugAsync ( slugOrId ) ;
235+
236+ if ( monograph == null )
237+ {
238+ monograph = await FindMonographAsync ( slugOrId ) ;
239+ if ( ! string . IsNullOrEmpty ( monograph ? . Slug ) )
240+ {
241+ return NotFound ( new
242+ {
243+ error = "invalid_id" ,
244+ error_description = $ "No such monograph found."
245+ } ) ;
246+ }
247+ }
248+
216249 if ( monograph == null || monograph . Deleted )
217250 {
218251 return NotFound ( new
@@ -317,6 +350,22 @@ await monographs.Collection.ReplaceOneAsync(
317350 return Ok ( ) ;
318351 }
319352
353+ [ HttpGet ( "{id}/publish-url" ) ]
354+ public async Task < IActionResult > GetPublishUrlAsync ( [ FromRoute ] string id )
355+ {
356+ var userId = this . User . GetUserId ( ) ;
357+ var monograph = await FindMonographAsync ( id ) ;
358+ if ( monograph == null || monograph . Deleted || monograph . UserId != userId )
359+ {
360+ return NotFound ( ) ;
361+ }
362+
363+ return Ok ( new
364+ {
365+ publishUrl = monograph . ConstructPublishUrl ( )
366+ } ) ;
367+ }
368+
320369 private static async Task MarkMonographForSyncAsync ( string userId , string monographId , string ? deviceId , string ? jti )
321370 {
322371 if ( deviceId == null ) return ;
0 commit comments