1- import { HttpContext } from '@adonisjs/core/http '
2- import { articleValidator } from '#validators/article_validator '
1+ import { ArticleStatus } from '#enums/article_status '
2+ import { Role } from '#enums/role '
33import Article from '#models/article'
4+ import ArticleStatsService from '#services/article_stats_service'
5+ import { articleValidator } from '#validators/article_validator'
6+ import { HttpContext } from '@adonisjs/core/http'
47import { DateTime } from 'luxon'
58
69export default class ArticlesController {
710 async index ( { inertia, request } : HttpContext ) {
811 const page = request . input ( 'page' , 1 )
912 const articles = await Article . query ( )
1013 . preload ( 'author' )
11- . where ( 'is_published ' , true )
14+ . where ( 'status ' , ArticleStatus . PUBLISHED )
1215 . orderBy ( 'published_at' , 'desc' )
1316 . paginate ( page , 10 )
1417
@@ -23,19 +26,20 @@ export default class ArticlesController {
2326
2427 async store ( { request, auth, response } : HttpContext ) {
2528 const data = await articleValidator . validate ( request . all ( ) )
26- const article = new Article ( )
27-
28- article . title = data . title
29- article . content = data . content
30- article . excerpt = data . excerpt
31- article . isPublished = data . isPublished || false
32- article . authorId = auth . user ! . id
33- if ( data . isPublished ) {
34- article . publishedAt = DateTime . now ( )
29+
30+ const payload : Partial < Article > = { ...data , authorId : auth . user ! . id }
31+
32+ if ( data . status === ArticleStatus . PUBLISHED ) {
33+ payload . publishedAt = DateTime . now ( )
3534 }
3635
37- await article . generateSlug ( )
38- await article . save ( )
36+ payload . slug = Article . generateSlug ( data . title )
37+
38+ console . log ( 'payload' , payload )
39+
40+ const article = await Article . create ( payload )
41+
42+ console . log ( 'article' , article )
3943
4044 return response . redirect ( ) . toRoute ( 'articles.show' , { slug : article . slug } )
4145 }
@@ -45,4 +49,204 @@ export default class ArticlesController {
4549
4650 return inertia . render ( 'articles/[slug]' , { article } )
4751 }
52+
53+ async dashboard ( { inertia, auth } : HttpContext ) {
54+ const isAdmin = auth . user ! . role === Role . ADMIN
55+ const stats = await ArticleStatsService . getStats ( auth . user ! . id , isAdmin )
56+ return inertia . render ( 'dashboard/index' , {
57+ publishedArticles : stats . published ,
58+ draftArticles : stats . drafts ,
59+ bannedArticles : stats . banned ,
60+ discussions : 0 ,
61+ questions : 0 ,
62+ } )
63+ }
64+
65+ async articles ( { inertia, request, auth } : HttpContext ) {
66+ const page = request . input ( 'page' , 1 )
67+ const status = request . input ( 'status' , null )
68+ const isAdmin = auth . user ! . role === Role . ADMIN
69+
70+ let query = Article . query ( ) . preload ( 'author' ) . orderBy ( 'created_at' , 'desc' )
71+
72+ // Logique différente selon le rôle
73+ if ( isAdmin ) {
74+ // Admin : voir tous les articles publiés/banned + ses propres brouillons
75+ if ( status && Object . values ( ArticleStatus ) . includes ( status as ArticleStatus ) ) {
76+ if ( status === ArticleStatus . PUBLISHED ) {
77+ // Voir tous les articles publiés (de tous les auteurs)
78+ query . where ( 'status' , ArticleStatus . PUBLISHED )
79+ } else if ( status === ArticleStatus . BANNED ) {
80+ // Voir tous les articles banned (de tous les auteurs)
81+ query . where ( 'status' , ArticleStatus . BANNED )
82+ } else {
83+ // Voir uniquement ses propres brouillons
84+ query . where ( 'status' , status as ArticleStatus ) . where ( 'author_id' , auth . user ! . id )
85+ }
86+ } else {
87+ // Par défaut : tous les publiés + ses brouillons
88+ query . where ( ( builder ) => {
89+ builder
90+ . where ( 'status' , ArticleStatus . PUBLISHED )
91+ . orWhere ( ( subBuilder ) => {
92+ subBuilder . where ( 'author_id' , auth . user ! . id ) . where ( 'status' , ArticleStatus . DRAFT )
93+ } )
94+ } )
95+ }
96+ } else {
97+ // Membre : voir uniquement ses propres articles
98+ query . where ( 'author_id' , auth . user ! . id )
99+
100+ if ( status && Object . values ( ArticleStatus ) . includes ( status as ArticleStatus ) ) {
101+ query . where ( 'status' , status as ArticleStatus )
102+ }
103+ }
104+
105+ const articles = await query . paginate ( page , 10 )
106+
107+ return inertia . render ( 'dashboard/articles' , {
108+ articles : articles . toJSON ( ) ,
109+ currentStatus : status ,
110+ isAdmin,
111+ } )
112+ }
113+
114+ async edit ( { inertia, params, auth, response } : HttpContext ) {
115+ const article = await Article . query ( )
116+ . where ( 'slug' , params . slug )
117+ . where ( 'author_id' , auth . user ! . id )
118+ . firstOrFail ( )
119+
120+ return inertia . render ( 'dashboard/articles/edit' , { article } )
121+ }
122+
123+ async update ( { request, params, auth, response } : HttpContext ) {
124+ const article = await Article . query ( )
125+ . where ( 'slug' , params . slug )
126+ . where ( 'author_id' , auth . user ! . id )
127+ . firstOrFail ( )
128+
129+ const data = await articleValidator . validate ( request . all ( ) )
130+
131+ const payload : Partial < Article > = { ...data }
132+
133+ // Si on passe de draft/waiting à published, mettre à jour publishedAt
134+ if (
135+ data . status === ArticleStatus . PUBLISHED &&
136+ article . status !== ArticleStatus . PUBLISHED
137+ ) {
138+ payload . publishedAt = DateTime . now ( )
139+ }
140+
141+ // Si le titre change, générer un nouveau slug
142+ if ( data . title !== article . title ) {
143+ payload . slug = Article . generateSlug ( data . title )
144+ }
145+
146+ await article . merge ( payload ) . save ( )
147+
148+ return response . redirect ( ) . toRoute ( 'articles.show' , { slug : article . slug } )
149+ }
150+
151+ // ADMIN METHODS
152+
153+ /**
154+ * Liste des articles pour l'admin
155+ * - Tous les articles publiés (de tous les auteurs)
156+ * - Ses propres brouillons seulement
157+ */
158+ async adminArticles ( { inertia, request, auth } : HttpContext ) {
159+ const page = request . input ( 'page' , 1 )
160+ const status = request . input ( 'status' , null )
161+
162+ let query = Article . query ( ) . preload ( 'author' ) . orderBy ( 'created_at' , 'desc' )
163+
164+ if ( status && Object . values ( ArticleStatus ) . includes ( status as ArticleStatus ) ) {
165+ if ( status === ArticleStatus . PUBLISHED ) {
166+ // Admin voit tous les articles publiés
167+ query . where ( 'status' , ArticleStatus . PUBLISHED )
168+ } else {
169+ // Admin ne voit que ses propres brouillons/en attente
170+ query . where ( 'status' , status as ArticleStatus ) . where ( 'author_id' , auth . user ! . id )
171+ }
172+ } else {
173+ // Par défaut : tous les publiés + ses brouillons
174+ query . where ( ( builder ) => {
175+ builder
176+ . where ( 'status' , ArticleStatus . PUBLISHED )
177+ . orWhere ( ( subBuilder ) => {
178+ subBuilder . where ( 'author_id' , auth . user ! . id ) . whereIn ( 'status' , [
179+ ArticleStatus . DRAFT ,
180+ ArticleStatus . WAITING_APPROVAL ,
181+ ] )
182+ } )
183+ } )
184+ }
185+
186+ const articles = await query . paginate ( page , 10 )
187+
188+ return inertia . render ( 'admin/articles' , {
189+ articles : articles . toJSON ( ) ,
190+ currentStatus : status ,
191+ } )
192+ }
193+
194+ /**
195+ * Dépublier un article (admin seulement)
196+ * Passe le statut de PUBLISHED à DRAFT
197+ */
198+ async unpublish ( { params, response, session, auth } : HttpContext ) {
199+ const article = await Article . query ( ) . where ( 'slug' , params . slug ) . firstOrFail ( )
200+
201+ // Vérifier que l'article est publié
202+ if ( article . status !== ArticleStatus . PUBLISHED ) {
203+ session . flash ( 'error' , 'Cet article n\'est pas publié' )
204+ return response . redirect ( ) . back ( )
205+ }
206+
207+ // Dépublier l'article
208+ article . status = ArticleStatus . DRAFT
209+ article . publishedAt = null
210+ await article . save ( )
211+
212+ session . flash ( 'success' , 'Article dépublié avec succès' )
213+ return response . redirect ( ) . back ( )
214+ }
215+
216+ /**
217+ * Bannir un article (admin seulement)
218+ */
219+ async ban ( { params, request, response, session } : HttpContext ) {
220+ const article = await Article . query ( ) . where ( 'slug' , params . slug ) . firstOrFail ( )
221+ const banReason = request . input ( 'ban_reason' )
222+
223+ article . status = ArticleStatus . BANNED
224+ article . banReason = banReason
225+ article . publishedAt = null
226+ await article . save ( )
227+
228+ session . flash ( 'success' , 'Article banni avec succès' )
229+ return response . redirect ( ) . back ( )
230+ }
231+
232+ /**
233+ * Débannir un article (admin seulement)
234+ */
235+ async unban ( { params, response, session } : HttpContext ) {
236+ const article = await Article . query ( ) . where ( 'slug' , params . slug ) . firstOrFail ( )
237+
238+ // Vérifier que l'article est banni
239+ if ( article . status !== ArticleStatus . BANNED ) {
240+ session . flash ( 'error' , 'Cet article n\'est pas banni' )
241+ return response . redirect ( ) . back ( )
242+ }
243+
244+ // Débannir l'article (le repasser en brouillon)
245+ article . status = ArticleStatus . DRAFT
246+ article . banReason = null
247+ await article . save ( )
248+
249+ session . flash ( 'success' , 'Article débanni avec succès' )
250+ return response . redirect ( ) . back ( )
251+ }
48252}
0 commit comments