mirror of
https://github.com/logos-messaging/OpChan.git
synced 2026-01-05 22:33:07 +00:00
chore: convert forum actions into a class
This commit is contained in:
parent
34279ff8b1
commit
635e3eb80a
@ -20,7 +20,7 @@ import {
|
|||||||
} from '@/components/ui/select';
|
} from '@/components/ui/select';
|
||||||
import { CypherImage } from './ui/CypherImage';
|
import { CypherImage } from './ui/CypherImage';
|
||||||
import { RelevanceIndicator } from './ui/relevance-indicator';
|
import { RelevanceIndicator } from './ui/relevance-indicator';
|
||||||
import { sortCells, SortOption } from '@/lib/forum/sorting';
|
import { sortCells, SortOption } from '@/lib/utils/sorting';
|
||||||
|
|
||||||
const CellList = () => {
|
const CellList = () => {
|
||||||
const { cells, isInitialLoading, posts, refreshData, isRefreshing } =
|
const { cells, isInitialLoading, posts, refreshData, isRefreshing } =
|
||||||
|
|||||||
@ -9,15 +9,7 @@ import { Cell, Post, Comment, OpchanMessage } from '@/types/forum';
|
|||||||
import { User, EVerificationStatus, DisplayPreference } from '@/types/identity';
|
import { User, EVerificationStatus, DisplayPreference } from '@/types/identity';
|
||||||
import { useToast } from '@/components/ui/use-toast';
|
import { useToast } from '@/components/ui/use-toast';
|
||||||
import { useAuth } from '@/contexts/useAuth';
|
import { useAuth } from '@/contexts/useAuth';
|
||||||
import {
|
import { ForumActions } from '@/lib/forum/ForumActions';
|
||||||
createPost,
|
|
||||||
createComment,
|
|
||||||
vote,
|
|
||||||
createCell,
|
|
||||||
moderatePost,
|
|
||||||
moderateComment,
|
|
||||||
moderateUser,
|
|
||||||
} from '@/lib/forum/actions';
|
|
||||||
import {
|
import {
|
||||||
setupPeriodicQueries,
|
setupPeriodicQueries,
|
||||||
monitorNetworkHealth,
|
monitorNetworkHealth,
|
||||||
@ -25,7 +17,7 @@ import {
|
|||||||
} from '@/lib/waku/network';
|
} from '@/lib/waku/network';
|
||||||
import messageManager from '@/lib/waku';
|
import messageManager from '@/lib/waku';
|
||||||
import { getDataFromCache } from '@/lib/forum/transformers';
|
import { getDataFromCache } from '@/lib/forum/transformers';
|
||||||
import { RelevanceCalculator } from '@/lib/forum/relevance';
|
import { RelevanceCalculator } from '@/lib/forum/RelevanceCalculator';
|
||||||
import { UserVerificationStatus } from '@/types/forum';
|
import { UserVerificationStatus } from '@/types/forum';
|
||||||
import { CryptoService } from '@/lib/services';
|
import { CryptoService } from '@/lib/services';
|
||||||
import { getEnsName } from '@wagmi/core';
|
import { getEnsName } from '@wagmi/core';
|
||||||
@ -107,6 +99,10 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
|
|||||||
const { currentUser, isAuthenticated } = useAuth();
|
const { currentUser, isAuthenticated } = useAuth();
|
||||||
|
|
||||||
const cryptoService = useMemo(() => new CryptoService(), []);
|
const cryptoService = useMemo(() => new CryptoService(), []);
|
||||||
|
const forumActions = useMemo(
|
||||||
|
() => new ForumActions(cryptoService),
|
||||||
|
[cryptoService]
|
||||||
|
);
|
||||||
|
|
||||||
// Transform message cache data to the expected types
|
// Transform message cache data to the expected types
|
||||||
const updateStateFromCache = useCallback(() => {
|
const updateStateFromCache = useCallback(() => {
|
||||||
@ -289,7 +285,7 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
|
|||||||
description: 'Sending your post to the network...',
|
description: 'Sending your post to the network...',
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await createPost(
|
const result = await forumActions.createPost(
|
||||||
{ cellId, title, content, currentUser, isAuthenticated },
|
{ cellId, title, content, currentUser, isAuthenticated },
|
||||||
updateStateFromCache
|
updateStateFromCache
|
||||||
);
|
);
|
||||||
@ -322,11 +318,8 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
|
|||||||
description: 'Sending your comment to the network...',
|
description: 'Sending your comment to the network...',
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await createComment(
|
const result = await forumActions.createComment(
|
||||||
postId,
|
{ postId, content, currentUser, isAuthenticated },
|
||||||
content,
|
|
||||||
currentUser,
|
|
||||||
isAuthenticated,
|
|
||||||
updateStateFromCache
|
updateStateFromCache
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -359,11 +352,8 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
|
|||||||
description: 'Recording your vote on the network...',
|
description: 'Recording your vote on the network...',
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await vote(
|
const result = await forumActions.vote(
|
||||||
postId,
|
{ targetId: postId, isUpvote, currentUser, isAuthenticated },
|
||||||
isUpvote,
|
|
||||||
currentUser,
|
|
||||||
isAuthenticated,
|
|
||||||
updateStateFromCache
|
updateStateFromCache
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -397,11 +387,8 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
|
|||||||
description: 'Recording your vote on the network...',
|
description: 'Recording your vote on the network...',
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await vote(
|
const result = await forumActions.vote(
|
||||||
commentId,
|
{ targetId: commentId, isUpvote, currentUser, isAuthenticated },
|
||||||
isUpvote,
|
|
||||||
currentUser,
|
|
||||||
isAuthenticated,
|
|
||||||
updateStateFromCache
|
updateStateFromCache
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -435,12 +422,8 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
|
|||||||
description: 'Sending your cell to the network...',
|
description: 'Sending your cell to the network...',
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await createCell(
|
const result = await forumActions.createCell(
|
||||||
name,
|
{ name, description, icon, currentUser, isAuthenticated },
|
||||||
description,
|
|
||||||
icon,
|
|
||||||
currentUser,
|
|
||||||
isAuthenticated,
|
|
||||||
updateStateFromCache
|
updateStateFromCache
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -473,13 +456,8 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
|
|||||||
description: 'Sending moderation message to the network...',
|
description: 'Sending moderation message to the network...',
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await moderatePost(
|
const result = await forumActions.moderatePost(
|
||||||
cellId,
|
{ cellId, postId, reason, currentUser, isAuthenticated, cellOwner },
|
||||||
postId,
|
|
||||||
reason,
|
|
||||||
currentUser,
|
|
||||||
isAuthenticated,
|
|
||||||
cellOwner,
|
|
||||||
updateStateFromCache
|
updateStateFromCache
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -511,13 +489,8 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
|
|||||||
description: 'Sending moderation message to the network...',
|
description: 'Sending moderation message to the network...',
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await moderateComment(
|
const result = await forumActions.moderateComment(
|
||||||
cellId,
|
{ cellId, commentId, reason, currentUser, isAuthenticated, cellOwner },
|
||||||
commentId,
|
|
||||||
reason,
|
|
||||||
currentUser,
|
|
||||||
isAuthenticated,
|
|
||||||
cellOwner,
|
|
||||||
updateStateFromCache
|
updateStateFromCache
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -544,13 +517,8 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
|
|||||||
reason: string | undefined,
|
reason: string | undefined,
|
||||||
cellOwner: string
|
cellOwner: string
|
||||||
) => {
|
) => {
|
||||||
const result = await moderateUser(
|
const result = await forumActions.moderateUser(
|
||||||
cellId,
|
{ cellId, userAddress, reason, currentUser, isAuthenticated, cellOwner },
|
||||||
userAddress,
|
|
||||||
reason,
|
|
||||||
currentUser,
|
|
||||||
isAuthenticated,
|
|
||||||
cellOwner,
|
|
||||||
updateStateFromCache
|
updateStateFromCache
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
534
src/lib/forum/ForumActions.ts
Normal file
534
src/lib/forum/ForumActions.ts
Normal file
@ -0,0 +1,534 @@
|
|||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
import {
|
||||||
|
MessageType,
|
||||||
|
UnsignedCellMessage,
|
||||||
|
UnsignedCommentMessage,
|
||||||
|
UnsignedPostMessage,
|
||||||
|
UnsignedVoteMessage,
|
||||||
|
UnsignedModerateMessage,
|
||||||
|
CellMessage,
|
||||||
|
CommentMessage,
|
||||||
|
PostMessage,
|
||||||
|
} from '@/types/waku';
|
||||||
|
import { Cell, Comment, Post } from '@/types/forum';
|
||||||
|
import { EVerificationStatus, User } from '@/types/identity';
|
||||||
|
import { transformCell, transformComment, transformPost } from './transformers';
|
||||||
|
import { MessageService, CryptoService } from '@/lib/services';
|
||||||
|
|
||||||
|
type ActionResult<T> = {
|
||||||
|
success: boolean;
|
||||||
|
data?: T;
|
||||||
|
error?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class ForumActions {
|
||||||
|
private cryptoService: CryptoService;
|
||||||
|
private messageService: MessageService;
|
||||||
|
|
||||||
|
constructor(cryptoService?: CryptoService) {
|
||||||
|
this.cryptoService = cryptoService || new CryptoService();
|
||||||
|
this.messageService = new MessageService(this.cryptoService);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------
|
||||||
|
POST / COMMENT / CELL CREATION
|
||||||
|
-------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
async createPost(
|
||||||
|
params: PostCreationParams,
|
||||||
|
updateStateFromCache: () => void
|
||||||
|
): Promise<ActionResult<Post>> {
|
||||||
|
const { cellId, title, content, currentUser, isAuthenticated } = params;
|
||||||
|
|
||||||
|
if (!isAuthenticated || !currentUser) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
'Authentication required. You need to connect your wallet to post.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user has basic verification or better, or owns ENS/Ordinal
|
||||||
|
const hasENSOrOrdinal = !!(
|
||||||
|
currentUser.ensDetails || currentUser.ordinalDetails
|
||||||
|
);
|
||||||
|
const isVerified =
|
||||||
|
currentUser.verificationStatus === EVerificationStatus.VERIFIED_OWNER ||
|
||||||
|
currentUser.verificationStatus === EVerificationStatus.VERIFIED_BASIC ||
|
||||||
|
hasENSOrOrdinal;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!isVerified &&
|
||||||
|
(currentUser.verificationStatus === EVerificationStatus.UNVERIFIED ||
|
||||||
|
currentUser.verificationStatus === EVerificationStatus.VERIFYING)
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
'Verification required. Please complete wallet verification to post.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const postId = uuidv4();
|
||||||
|
const postMessage: UnsignedPostMessage = {
|
||||||
|
type: MessageType.POST,
|
||||||
|
id: postId,
|
||||||
|
cellId,
|
||||||
|
title,
|
||||||
|
content,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
author: currentUser.address,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await this.messageService.sendMessage(postMessage);
|
||||||
|
if (!result.success) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: result.error || 'Failed to create post. Please try again.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStateFromCache();
|
||||||
|
const transformedPost = transformPost(result.message! as PostMessage);
|
||||||
|
if (!transformedPost) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'Failed to transform post data.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: transformedPost,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating post:', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'Failed to create post. Please try again.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async createComment(
|
||||||
|
params: CommentCreationParams,
|
||||||
|
updateStateFromCache: () => void
|
||||||
|
): Promise<ActionResult<Comment>> {
|
||||||
|
const { postId, content, currentUser, isAuthenticated } = params;
|
||||||
|
|
||||||
|
if (!isAuthenticated || !currentUser) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
'Authentication required. You need to connect your wallet to comment.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user has basic verification or better, or owns ENS/Ordinal
|
||||||
|
const hasENSOrOrdinal = !!(
|
||||||
|
currentUser.ensDetails || currentUser.ordinalDetails
|
||||||
|
);
|
||||||
|
const isVerified =
|
||||||
|
currentUser.verificationStatus === EVerificationStatus.VERIFIED_OWNER ||
|
||||||
|
currentUser.verificationStatus === EVerificationStatus.VERIFIED_BASIC ||
|
||||||
|
hasENSOrOrdinal;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!isVerified &&
|
||||||
|
(currentUser.verificationStatus === EVerificationStatus.UNVERIFIED ||
|
||||||
|
currentUser.verificationStatus === EVerificationStatus.VERIFYING)
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
'Verification required. Please complete wallet verification to comment.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const commentId = uuidv4();
|
||||||
|
const commentMessage: UnsignedCommentMessage = {
|
||||||
|
type: MessageType.COMMENT,
|
||||||
|
id: commentId,
|
||||||
|
postId,
|
||||||
|
content,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
author: currentUser.address,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await this.messageService.sendMessage(commentMessage);
|
||||||
|
if (!result.success) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: result.error || 'Failed to add comment. Please try again.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStateFromCache();
|
||||||
|
const transformedComment = transformComment(
|
||||||
|
result.message! as CommentMessage
|
||||||
|
);
|
||||||
|
if (!transformedComment) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'Failed to transform comment data.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: transformedComment,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating comment:', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'Failed to add comment. Please try again.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async createCell(
|
||||||
|
params: CellCreationParams,
|
||||||
|
updateStateFromCache: () => void
|
||||||
|
): Promise<ActionResult<Cell>> {
|
||||||
|
const { name, description, icon, currentUser, isAuthenticated } = params;
|
||||||
|
|
||||||
|
if (!isAuthenticated || !currentUser) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
'Authentication required. You need to verify Ordinal ownership to create a cell.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const cellId = uuidv4();
|
||||||
|
const cellMessage: UnsignedCellMessage = {
|
||||||
|
type: MessageType.CELL,
|
||||||
|
id: cellId,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
...(icon && { icon }),
|
||||||
|
timestamp: Date.now(),
|
||||||
|
author: currentUser.address,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await this.messageService.sendMessage(cellMessage);
|
||||||
|
if (!result.success) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: result.error || 'Failed to create cell. Please try again.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStateFromCache();
|
||||||
|
const transformedCell = transformCell(result.message! as CellMessage);
|
||||||
|
if (!transformedCell) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'Failed to transform cell data.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: transformedCell,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating cell:', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'Failed to create cell. Please try again.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------
|
||||||
|
VOTING
|
||||||
|
-------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
async vote(
|
||||||
|
params: VoteParams,
|
||||||
|
updateStateFromCache: () => void
|
||||||
|
): Promise<ActionResult<boolean>> {
|
||||||
|
const { targetId, isUpvote, currentUser, isAuthenticated } = params;
|
||||||
|
|
||||||
|
if (!isAuthenticated || !currentUser) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
'Authentication required. You need to connect your wallet to vote.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user has basic verification or better, or owns ENS/Ordinal
|
||||||
|
const hasENSOrOrdinal = !!(
|
||||||
|
currentUser.ensDetails || currentUser.ordinalDetails
|
||||||
|
);
|
||||||
|
const isVerified =
|
||||||
|
currentUser.verificationStatus === EVerificationStatus.VERIFIED_OWNER ||
|
||||||
|
currentUser.verificationStatus === EVerificationStatus.VERIFIED_BASIC ||
|
||||||
|
hasENSOrOrdinal;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!isVerified &&
|
||||||
|
(currentUser.verificationStatus === EVerificationStatus.UNVERIFIED ||
|
||||||
|
currentUser.verificationStatus === EVerificationStatus.VERIFYING)
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
'Verification required. Please complete wallet verification to vote.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const voteId = uuidv4();
|
||||||
|
const voteMessage: UnsignedVoteMessage = {
|
||||||
|
type: MessageType.VOTE,
|
||||||
|
id: voteId,
|
||||||
|
targetId,
|
||||||
|
value: isUpvote ? 1 : -1,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
author: currentUser.address,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await this.messageService.sendMessage(voteMessage);
|
||||||
|
if (!result.success) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
result.error || 'Failed to register your vote. Please try again.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStateFromCache();
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: true,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error voting:', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'Failed to register your vote. Please try again.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------
|
||||||
|
MODERATION
|
||||||
|
-------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
async moderatePost(
|
||||||
|
params: PostModerationParams,
|
||||||
|
updateStateFromCache: () => void
|
||||||
|
): Promise<ActionResult<boolean>> {
|
||||||
|
const { cellId, postId, reason, currentUser, isAuthenticated, cellOwner } = params;
|
||||||
|
|
||||||
|
if (!isAuthenticated || !currentUser) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
'Authentication required. You need to verify Ordinal ownership to moderate posts.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (currentUser.address !== cellOwner) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'Not authorized. Only the cell admin can moderate posts.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const modMsg: UnsignedModerateMessage = {
|
||||||
|
type: MessageType.MODERATE,
|
||||||
|
id: uuidv4(),
|
||||||
|
cellId,
|
||||||
|
targetType: 'post',
|
||||||
|
targetId: postId,
|
||||||
|
reason,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
author: currentUser.address,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await this.messageService.sendMessage(modMsg);
|
||||||
|
if (!result.success) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: result.error || 'Failed to moderate post. Please try again.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStateFromCache();
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: true,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error moderating post:', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'Failed to moderate post. Please try again.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async moderateComment(
|
||||||
|
params: CommentModerationParams,
|
||||||
|
updateStateFromCache: () => void
|
||||||
|
): Promise<ActionResult<boolean>> {
|
||||||
|
const { cellId, commentId, reason, currentUser, isAuthenticated, cellOwner } = params;
|
||||||
|
|
||||||
|
if (!isAuthenticated || !currentUser) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
'Authentication required. You need to verify Ordinal ownership to moderate comments.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (currentUser.address !== cellOwner) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'Not authorized. Only the cell admin can moderate comments.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const modMsg: UnsignedModerateMessage = {
|
||||||
|
type: MessageType.MODERATE,
|
||||||
|
id: uuidv4(),
|
||||||
|
cellId,
|
||||||
|
targetType: 'comment',
|
||||||
|
targetId: commentId,
|
||||||
|
reason,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
author: currentUser.address,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await this.messageService.sendMessage(modMsg);
|
||||||
|
if (!result.success) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
result.error || 'Failed to moderate comment. Please try again.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStateFromCache();
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: true,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error moderating comment:', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'Failed to moderate comment. Please try again.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async moderateUser(
|
||||||
|
params: UserModerationParams,
|
||||||
|
updateStateFromCache: () => void
|
||||||
|
): Promise<ActionResult<boolean>> {
|
||||||
|
const { cellId, userAddress, reason, currentUser, isAuthenticated, cellOwner } = params;
|
||||||
|
|
||||||
|
if (!isAuthenticated || !currentUser) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
'Authentication required. You need to verify Ordinal ownership to moderate users.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (currentUser.address !== cellOwner) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'Not authorized. Only the cell admin can moderate users.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const modMsg: UnsignedModerateMessage = {
|
||||||
|
type: MessageType.MODERATE,
|
||||||
|
id: uuidv4(),
|
||||||
|
cellId,
|
||||||
|
targetType: 'user',
|
||||||
|
targetId: userAddress,
|
||||||
|
reason,
|
||||||
|
author: currentUser.address,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await this.messageService.sendMessage(modMsg);
|
||||||
|
if (!result.success) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: result.error || 'Failed to moderate user. Please try again.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStateFromCache();
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: true,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error moderating user:', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'Failed to moderate user. Please try again.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base interface for all actions that require user authentication
|
||||||
|
interface BaseActionParams {
|
||||||
|
currentUser: User | null;
|
||||||
|
isAuthenticated: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parameter interfaces for all action methods
|
||||||
|
interface PostCreationParams extends BaseActionParams {
|
||||||
|
cellId: string;
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CommentCreationParams extends BaseActionParams {
|
||||||
|
postId: string;
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CellCreationParams extends BaseActionParams {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
icon?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VoteParams extends BaseActionParams {
|
||||||
|
targetId: string;
|
||||||
|
isUpvote: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PostModerationParams extends BaseActionParams {
|
||||||
|
cellId: string;
|
||||||
|
postId: string;
|
||||||
|
reason?: string;
|
||||||
|
cellOwner: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CommentModerationParams extends BaseActionParams {
|
||||||
|
cellId: string;
|
||||||
|
commentId: string;
|
||||||
|
reason?: string;
|
||||||
|
cellOwner: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UserModerationParams extends BaseActionParams {
|
||||||
|
cellId: string;
|
||||||
|
userAddress: string;
|
||||||
|
reason?: string;
|
||||||
|
cellOwner: string;
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { RelevanceCalculator } from '../relevance';
|
import { RelevanceCalculator } from '../RelevanceCalculator';
|
||||||
import { Post, Comment, UserVerificationStatus } from '@/types/forum';
|
import { Post, Comment, UserVerificationStatus } from '@/types/forum';
|
||||||
import { User, EVerificationStatus, DisplayPreference } from '@/types/identity';
|
import { User, EVerificationStatus, DisplayPreference } from '@/types/identity';
|
||||||
import { VoteMessage, MessageType } from '@/types/waku';
|
import { VoteMessage, MessageType } from '@/types/waku';
|
||||||
|
|||||||
@ -1,504 +0,0 @@
|
|||||||
import { v4 as uuidv4 } from 'uuid';
|
|
||||||
import {
|
|
||||||
MessageType,
|
|
||||||
UnsignedCellMessage,
|
|
||||||
UnsignedCommentMessage,
|
|
||||||
UnsignedPostMessage,
|
|
||||||
UnsignedVoteMessage,
|
|
||||||
UnsignedModerateMessage,
|
|
||||||
CellMessage,
|
|
||||||
CommentMessage,
|
|
||||||
PostMessage,
|
|
||||||
} from '@/types/waku';
|
|
||||||
import { Cell, Comment, Post } from '@/types/forum';
|
|
||||||
import { EVerificationStatus, User } from '@/types/identity';
|
|
||||||
import { transformCell, transformComment, transformPost } from './transformers';
|
|
||||||
import { MessageService, CryptoService } from '@/lib/services';
|
|
||||||
|
|
||||||
// Result types for action functions
|
|
||||||
type ActionResult<T> = {
|
|
||||||
success: boolean;
|
|
||||||
data?: T;
|
|
||||||
error?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------
|
|
||||||
POST / COMMENT / CELL CREATION
|
|
||||||
-------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
interface PostCreationParams {
|
|
||||||
cellId: string;
|
|
||||||
title: string;
|
|
||||||
content: string;
|
|
||||||
currentUser: User | null;
|
|
||||||
isAuthenticated: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createPost = async (
|
|
||||||
{ cellId, title, content, currentUser, isAuthenticated }: PostCreationParams,
|
|
||||||
updateStateFromCache: () => void
|
|
||||||
): Promise<ActionResult<Post>> => {
|
|
||||||
if (!isAuthenticated || !currentUser) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error:
|
|
||||||
'Authentication required. You need to connect your wallet to post.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if user has basic verification or better, or owns ENS/Ordinal
|
|
||||||
const hasENSOrOrdinal = !!(
|
|
||||||
currentUser.ensDetails || currentUser.ordinalDetails
|
|
||||||
);
|
|
||||||
const isVerified =
|
|
||||||
currentUser.verificationStatus === EVerificationStatus.VERIFIED_OWNER ||
|
|
||||||
currentUser.verificationStatus === EVerificationStatus.VERIFIED_BASIC ||
|
|
||||||
hasENSOrOrdinal;
|
|
||||||
|
|
||||||
if (
|
|
||||||
!isVerified &&
|
|
||||||
(currentUser.verificationStatus === EVerificationStatus.UNVERIFIED ||
|
|
||||||
currentUser.verificationStatus === EVerificationStatus.VERIFYING)
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error:
|
|
||||||
'Verification required. Please complete wallet verification to post.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const postId = uuidv4();
|
|
||||||
const postMessage: UnsignedPostMessage = {
|
|
||||||
type: MessageType.POST,
|
|
||||||
id: postId,
|
|
||||||
cellId,
|
|
||||||
title,
|
|
||||||
content,
|
|
||||||
timestamp: Date.now(),
|
|
||||||
author: currentUser.address,
|
|
||||||
};
|
|
||||||
|
|
||||||
const cryptoService = new CryptoService();
|
|
||||||
const messageService = new MessageService(cryptoService);
|
|
||||||
const result = await messageService.sendMessage(postMessage);
|
|
||||||
if (!result.success) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: result.error || 'Failed to create post. Please try again.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
updateStateFromCache();
|
|
||||||
const transformedPost = transformPost(result.message! as PostMessage);
|
|
||||||
if (!transformedPost) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: 'Failed to transform post data.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: transformedPost,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error creating post:', error);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: 'Failed to create post. Please try again.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createComment = async (
|
|
||||||
postId: string,
|
|
||||||
content: string,
|
|
||||||
currentUser: User | null,
|
|
||||||
isAuthenticated: boolean,
|
|
||||||
updateStateFromCache: () => void
|
|
||||||
): Promise<ActionResult<Comment>> => {
|
|
||||||
if (!isAuthenticated || !currentUser) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error:
|
|
||||||
'Authentication required. You need to connect your wallet to comment.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if user has basic verification or better, or owns ENS/Ordinal
|
|
||||||
const hasENSOrOrdinal = !!(
|
|
||||||
currentUser.ensDetails || currentUser.ordinalDetails
|
|
||||||
);
|
|
||||||
const isVerified =
|
|
||||||
currentUser.verificationStatus === EVerificationStatus.VERIFIED_OWNER ||
|
|
||||||
currentUser.verificationStatus === EVerificationStatus.VERIFIED_BASIC ||
|
|
||||||
hasENSOrOrdinal;
|
|
||||||
|
|
||||||
if (
|
|
||||||
!isVerified &&
|
|
||||||
(currentUser.verificationStatus === EVerificationStatus.UNVERIFIED ||
|
|
||||||
currentUser.verificationStatus === EVerificationStatus.VERIFYING)
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error:
|
|
||||||
'Verification required. Please complete wallet verification to comment.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const commentId = uuidv4();
|
|
||||||
const commentMessage: UnsignedCommentMessage = {
|
|
||||||
type: MessageType.COMMENT,
|
|
||||||
id: commentId,
|
|
||||||
postId,
|
|
||||||
content,
|
|
||||||
timestamp: Date.now(),
|
|
||||||
author: currentUser.address,
|
|
||||||
};
|
|
||||||
|
|
||||||
const cryptoService = new CryptoService();
|
|
||||||
const messageService = new MessageService(cryptoService);
|
|
||||||
const result = await messageService.sendMessage(commentMessage);
|
|
||||||
if (!result.success) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: result.error || 'Failed to add comment. Please try again.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
updateStateFromCache();
|
|
||||||
const transformedComment = transformComment(
|
|
||||||
result.message! as CommentMessage
|
|
||||||
);
|
|
||||||
if (!transformedComment) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: 'Failed to transform comment data.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: transformedComment,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error creating comment:', error);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: 'Failed to add comment. Please try again.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createCell = async (
|
|
||||||
name: string,
|
|
||||||
description: string,
|
|
||||||
icon: string | undefined,
|
|
||||||
currentUser: User | null,
|
|
||||||
isAuthenticated: boolean,
|
|
||||||
updateStateFromCache: () => void
|
|
||||||
): Promise<ActionResult<Cell>> => {
|
|
||||||
if (!isAuthenticated || !currentUser) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error:
|
|
||||||
'Authentication required. You need to verify Ordinal ownership to create a cell.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const cellId = uuidv4();
|
|
||||||
const cellMessage: UnsignedCellMessage = {
|
|
||||||
type: MessageType.CELL,
|
|
||||||
id: cellId,
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
...(icon && { icon }),
|
|
||||||
timestamp: Date.now(),
|
|
||||||
author: currentUser.address,
|
|
||||||
};
|
|
||||||
|
|
||||||
const cryptoService = new CryptoService();
|
|
||||||
const messageService = new MessageService(cryptoService);
|
|
||||||
const result = await messageService.sendMessage(cellMessage);
|
|
||||||
if (!result.success) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: result.error || 'Failed to create cell. Please try again.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
updateStateFromCache();
|
|
||||||
const transformedCell = transformCell(result.message! as CellMessage);
|
|
||||||
if (!transformedCell) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: 'Failed to transform cell data.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: transformedCell,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error creating cell:', error);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: 'Failed to create cell. Please try again.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------
|
|
||||||
VOTING
|
|
||||||
-------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
export const vote = async (
|
|
||||||
targetId: string,
|
|
||||||
isUpvote: boolean,
|
|
||||||
currentUser: User | null,
|
|
||||||
isAuthenticated: boolean,
|
|
||||||
updateStateFromCache: () => void
|
|
||||||
): Promise<ActionResult<boolean>> => {
|
|
||||||
if (!isAuthenticated || !currentUser) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error:
|
|
||||||
'Authentication required. You need to connect your wallet to vote.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if user has basic verification or better, or owns ENS/Ordinal
|
|
||||||
const hasENSOrOrdinal = !!(
|
|
||||||
currentUser.ensDetails || currentUser.ordinalDetails
|
|
||||||
);
|
|
||||||
const isVerified =
|
|
||||||
currentUser.verificationStatus === EVerificationStatus.VERIFIED_OWNER ||
|
|
||||||
currentUser.verificationStatus === EVerificationStatus.VERIFIED_BASIC ||
|
|
||||||
hasENSOrOrdinal;
|
|
||||||
|
|
||||||
if (
|
|
||||||
!isVerified &&
|
|
||||||
(currentUser.verificationStatus === EVerificationStatus.UNVERIFIED ||
|
|
||||||
currentUser.verificationStatus === EVerificationStatus.VERIFYING)
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error:
|
|
||||||
'Verification required. Please complete wallet verification to vote.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const voteId = uuidv4();
|
|
||||||
const voteMessage: UnsignedVoteMessage = {
|
|
||||||
type: MessageType.VOTE,
|
|
||||||
id: voteId,
|
|
||||||
targetId,
|
|
||||||
value: isUpvote ? 1 : -1,
|
|
||||||
timestamp: Date.now(),
|
|
||||||
author: currentUser.address,
|
|
||||||
};
|
|
||||||
|
|
||||||
const cryptoService = new CryptoService();
|
|
||||||
const messageService = new MessageService(cryptoService);
|
|
||||||
const result = await messageService.sendMessage(voteMessage);
|
|
||||||
if (!result.success) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error:
|
|
||||||
result.error || 'Failed to register your vote. Please try again.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
updateStateFromCache();
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: true,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error voting:', error);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: 'Failed to register your vote. Please try again.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------
|
|
||||||
MODERATION
|
|
||||||
-------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
export const moderatePost = async (
|
|
||||||
cellId: string,
|
|
||||||
postId: string,
|
|
||||||
reason: string | undefined,
|
|
||||||
currentUser: User | null,
|
|
||||||
isAuthenticated: boolean,
|
|
||||||
cellOwner: string,
|
|
||||||
updateStateFromCache: () => void
|
|
||||||
): Promise<ActionResult<boolean>> => {
|
|
||||||
if (!isAuthenticated || !currentUser) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error:
|
|
||||||
'Authentication required. You need to verify Ordinal ownership to moderate posts.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (currentUser.address !== cellOwner) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: 'Not authorized. Only the cell admin can moderate posts.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const modMsg: UnsignedModerateMessage = {
|
|
||||||
type: MessageType.MODERATE,
|
|
||||||
id: uuidv4(),
|
|
||||||
cellId,
|
|
||||||
targetType: 'post',
|
|
||||||
targetId: postId,
|
|
||||||
reason,
|
|
||||||
timestamp: Date.now(),
|
|
||||||
author: currentUser.address,
|
|
||||||
};
|
|
||||||
const cryptoService = new CryptoService();
|
|
||||||
const messageService = new MessageService(cryptoService);
|
|
||||||
const result = await messageService.sendMessage(modMsg);
|
|
||||||
if (!result.success) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: result.error || 'Failed to moderate post. Please try again.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
updateStateFromCache();
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: true,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error moderating post:', error);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: 'Failed to moderate post. Please try again.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const moderateComment = async (
|
|
||||||
cellId: string,
|
|
||||||
commentId: string,
|
|
||||||
reason: string | undefined,
|
|
||||||
currentUser: User | null,
|
|
||||||
isAuthenticated: boolean,
|
|
||||||
cellOwner: string,
|
|
||||||
updateStateFromCache: () => void
|
|
||||||
): Promise<ActionResult<boolean>> => {
|
|
||||||
if (!isAuthenticated || !currentUser) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error:
|
|
||||||
'Authentication required. You need to verify Ordinal ownership to moderate comments.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (currentUser.address !== cellOwner) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: 'Not authorized. Only the cell admin can moderate comments.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const modMsg: UnsignedModerateMessage = {
|
|
||||||
type: MessageType.MODERATE,
|
|
||||||
id: uuidv4(),
|
|
||||||
cellId,
|
|
||||||
targetType: 'comment',
|
|
||||||
targetId: commentId,
|
|
||||||
reason,
|
|
||||||
timestamp: Date.now(),
|
|
||||||
author: currentUser.address,
|
|
||||||
};
|
|
||||||
const cryptoService = new CryptoService();
|
|
||||||
const messageService = new MessageService(cryptoService);
|
|
||||||
const result = await messageService.sendMessage(modMsg);
|
|
||||||
if (!result.success) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: result.error || 'Failed to moderate comment. Please try again.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
updateStateFromCache();
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: true,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error moderating comment:', error);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: 'Failed to moderate comment. Please try again.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const moderateUser = async (
|
|
||||||
cellId: string,
|
|
||||||
userAddress: string,
|
|
||||||
reason: string | undefined,
|
|
||||||
currentUser: User | null,
|
|
||||||
isAuthenticated: boolean,
|
|
||||||
cellOwner: string,
|
|
||||||
updateStateFromCache: () => void
|
|
||||||
): Promise<ActionResult<boolean>> => {
|
|
||||||
if (!isAuthenticated || !currentUser) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error:
|
|
||||||
'Authentication required. You need to verify Ordinal ownership to moderate users.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (currentUser.address !== cellOwner) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: 'Not authorized. Only the cell admin can moderate users.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const modMsg: UnsignedModerateMessage = {
|
|
||||||
type: MessageType.MODERATE,
|
|
||||||
id: uuidv4(),
|
|
||||||
cellId,
|
|
||||||
targetType: 'user',
|
|
||||||
targetId: userAddress,
|
|
||||||
reason,
|
|
||||||
author: currentUser.address,
|
|
||||||
timestamp: Date.now(),
|
|
||||||
};
|
|
||||||
const cryptoService = new CryptoService();
|
|
||||||
const messageService = new MessageService(cryptoService);
|
|
||||||
const result = await messageService.sendMessage(modMsg);
|
|
||||||
if (!result.success) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: result.error || 'Failed to moderate user. Please try again.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
updateStateFromCache();
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: true,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error moderating user:', error);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: 'Failed to moderate user. Please try again.',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -6,7 +6,7 @@ import {
|
|||||||
VoteMessage,
|
VoteMessage,
|
||||||
} from '@/types/waku';
|
} from '@/types/waku';
|
||||||
import messageManager from '@/lib/waku';
|
import messageManager from '@/lib/waku';
|
||||||
import { RelevanceCalculator } from './relevance';
|
import { RelevanceCalculator } from './RelevanceCalculator';
|
||||||
import { UserVerificationStatus } from '@/types/forum';
|
import { UserVerificationStatus } from '@/types/forum';
|
||||||
import { MessageValidator } from '@/lib/utils/MessageValidator';
|
import { MessageValidator } from '@/lib/utils/MessageValidator';
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import PostCard from '@/components/PostCard';
|
|||||||
import FeedSidebar from '@/components/FeedSidebar';
|
import FeedSidebar from '@/components/FeedSidebar';
|
||||||
import { useForum } from '@/contexts/useForum';
|
import { useForum } from '@/contexts/useForum';
|
||||||
import { useAuth } from '@/contexts/useAuth';
|
import { useAuth } from '@/contexts/useAuth';
|
||||||
import { sortPosts, SortOption } from '@/lib/forum/sorting';
|
import { sortPosts, SortOption } from '@/lib/utils/sorting';
|
||||||
|
|
||||||
const FeedPage: React.FC = () => {
|
const FeedPage: React.FC = () => {
|
||||||
const { posts, comments, isInitialLoading, isRefreshing, refreshData } =
|
const { posts, comments, isInitialLoading, isRefreshing, refreshData } =
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user