diff --git a/frontend/src/components/post.tsx b/frontend/src/components/post.tsx index 615c562..2de5394 100644 --- a/frontend/src/components/post.tsx +++ b/frontend/src/components/post.tsx @@ -9,6 +9,7 @@ import {useAuth} from "../utils/useAuth"; import Feed from "../actors/feed"; import React, {useEffect, useState} from "react"; import {CommentForm} from "./Modal/commentForm"; +import {useNavigate} from "react-router-dom"; export default function Post(props: { content: PostImmutable, setPostItem?: Function, avatar?: string, name?: string }) { const {content, setPostItem} = props @@ -19,6 +20,7 @@ export default function Post(props: { content: PostImmutable, setPostItem?: Func useEffect(() => { setData(content) }, [content]) + const navigate = useNavigate(); const feedApi = React.useMemo(() => { if (!userFeedCai) return undefined @@ -58,6 +60,7 @@ export default function Post(props: { content: PostImmutable, setPostItem?: Func }} onClick={() => setPostItem?.(data)}> navigate(`/profile/${content.user.toString()}`)} size={32} src={props.avatar ? props.avatar : "https://avatars.githubusercontent.com/u/120618331?s=200&v=4"} style={{ diff --git a/frontend/src/declarations/bucket/bucket.did b/frontend/src/declarations/bucket/bucket.did index c64ef86..d484c25 100644 --- a/frontend/src/declarations/bucket/bucket.did +++ b/frontend/src/declarations/bucket/bucket.did @@ -10,11 +10,11 @@ type PostImmutable = comment: vec Comment; content: text; createdAt: Time; + feedCanister: principal; index: nat; like: vec Like; postId: PostId; repost: vec Repost; - title: text; user: UserId; }; type PostId = text; diff --git a/frontend/src/declarations/bucket/bucket.did.js b/frontend/src/declarations/bucket/bucket.did.js index 867d6e4..4f22e23 100644 --- a/frontend/src/declarations/bucket/bucket.did.js +++ b/frontend/src/declarations/bucket/bucket.did.js @@ -11,13 +11,13 @@ export const idlFactory = ({ IDL }) => { const PostId = IDL.Text; const PostImmutable = IDL.Record({ 'repost' : IDL.Vec(Repost), - 'title' : IDL.Text, 'content' : IDL.Text, 'like' : IDL.Vec(Like), 'createdAt' : Time, 'user' : UserId, 'comment' : IDL.Vec(Comment), 'index' : IDL.Nat, + 'feedCanister' : IDL.Principal, 'postId' : PostId, }); const NewComment = IDL.Vec(Comment); diff --git a/frontend/src/declarations/bucket/bucket.ts b/frontend/src/declarations/bucket/bucket.ts index 7818ecd..460bbde 100644 --- a/frontend/src/declarations/bucket/bucket.ts +++ b/frontend/src/declarations/bucket/bucket.ts @@ -28,13 +28,13 @@ export type NewRepost = Array; export type PostId = string; export interface PostImmutable { 'repost' : Array, - 'title' : string, 'content' : string, 'like' : Array, 'createdAt' : Time, 'user' : UserId, 'comment' : Array, 'index' : bigint, + 'feedCanister' : Principal, 'postId' : PostId, } export interface Repost { 'createdAt' : Time, 'user' : UserId } diff --git a/frontend/src/declarations/bucket/index.d.ts b/frontend/src/declarations/bucket/index.d.ts index f81adfd..dcbeba2 100644 --- a/frontend/src/declarations/bucket/index.d.ts +++ b/frontend/src/declarations/bucket/index.d.ts @@ -7,7 +7,7 @@ import type { import type { Principal } from "@dfinity/principal"; import type { IDL } from "@dfinity/candid"; -import { _SERVICE } from './bucket'; +import { _SERVICE } from './bucket.did'; export declare const idlFactory: IDL.InterfaceFactory; export declare const canisterId: string; diff --git a/frontend/src/declarations/commentFetch/commentFetch.did b/frontend/src/declarations/commentFetch/commentFetch.did index 35cc28b..82ed5e1 100644 --- a/frontend/src/declarations/commentFetch/commentFetch.did +++ b/frontend/src/declarations/commentFetch/commentFetch.did @@ -10,11 +10,11 @@ type PostImmutable = comment: vec Comment; content: text; createdAt: Time; + feedCanister: principal; index: nat; like: vec Like; postId: PostId; repost: vec Repost; - title: text; user: UserId; }; type PostId = text; diff --git a/frontend/src/declarations/commentFetch/commentFetch.did.d.ts b/frontend/src/declarations/commentFetch/commentFetch.did.d.ts index cf54537..b3bc2a4 100644 --- a/frontend/src/declarations/commentFetch/commentFetch.did.d.ts +++ b/frontend/src/declarations/commentFetch/commentFetch.did.d.ts @@ -22,13 +22,13 @@ export interface Like { 'createdAt' : Time, 'user' : UserId } export type PostId = string; export interface PostImmutable { 'repost' : Array, - 'title' : string, 'content' : string, 'like' : Array, 'createdAt' : Time, 'user' : UserId, 'comment' : Array, 'index' : bigint, + 'feedCanister' : Principal, 'postId' : PostId, } export interface Repost { 'createdAt' : Time, 'user' : UserId } diff --git a/frontend/src/declarations/commentFetch/commentFetch.did.js b/frontend/src/declarations/commentFetch/commentFetch.did.js index 9a9b5d2..ad978c4 100644 --- a/frontend/src/declarations/commentFetch/commentFetch.did.js +++ b/frontend/src/declarations/commentFetch/commentFetch.did.js @@ -11,13 +11,13 @@ export const idlFactory = ({ IDL }) => { const PostId = IDL.Text; const PostImmutable = IDL.Record({ 'repost' : IDL.Vec(Repost), - 'title' : IDL.Text, 'content' : IDL.Text, 'like' : IDL.Vec(Like), 'createdAt' : Time, 'user' : UserId, 'comment' : IDL.Vec(Comment), 'index' : IDL.Nat, + 'feedCanister' : IDL.Principal, 'postId' : PostId, }); const CommentFetch = IDL.Service({ diff --git a/frontend/src/declarations/feed/feed.did b/frontend/src/declarations/feed/feed.did index d1d5df4..888b9ed 100644 --- a/frontend/src/declarations/feed/feed.did +++ b/frontend/src/declarations/feed/feed.did @@ -10,11 +10,11 @@ type PostImmutable = comment: vec Comment; content: text; createdAt: Time; + feedCanister: principal; index: nat; like: vec Like; postId: PostId; repost: vec Repost; - title: text; user: UserId; }; type PostId = text; diff --git a/frontend/src/declarations/feed/feed.did.js b/frontend/src/declarations/feed/feed.did.js index bed1396..9b4e76b 100644 --- a/frontend/src/declarations/feed/feed.did.js +++ b/frontend/src/declarations/feed/feed.did.js @@ -11,13 +11,13 @@ export const idlFactory = ({ IDL }) => { const PostId = IDL.Text; const PostImmutable = IDL.Record({ 'repost' : IDL.Vec(Repost), - 'title' : IDL.Text, 'content' : IDL.Text, 'like' : IDL.Vec(Like), 'createdAt' : Time, 'user' : UserId, 'comment' : IDL.Vec(Comment), 'index' : IDL.Nat, + 'feedCanister' : IDL.Principal, 'postId' : PostId, }); const Feed = IDL.Service({ diff --git a/frontend/src/declarations/feed/feed.ts b/frontend/src/declarations/feed/feed.ts index a900014..1d029af 100644 --- a/frontend/src/declarations/feed/feed.ts +++ b/frontend/src/declarations/feed/feed.ts @@ -41,13 +41,13 @@ export interface Like { 'createdAt' : Time, 'user' : UserId } export type PostId = string; export interface PostImmutable { 'repost' : Array, - 'title' : string, 'content' : string, 'like' : Array, 'createdAt' : Time, 'user' : UserId, 'comment' : Array, 'index' : bigint, + 'feedCanister' : Principal, 'postId' : PostId, } export interface Repost { 'createdAt' : Time, 'user' : UserId } diff --git a/frontend/src/declarations/feed/index.d.ts b/frontend/src/declarations/feed/index.d.ts index 8d31631..c193dd1 100644 --- a/frontend/src/declarations/feed/index.d.ts +++ b/frontend/src/declarations/feed/index.d.ts @@ -7,7 +7,7 @@ import type { import type { Principal } from "@dfinity/principal"; import type { IDL } from "@dfinity/candid"; -import { _SERVICE } from './feed'; +import { _SERVICE } from './feed.did'; export declare const idlFactory: IDL.InterfaceFactory; export declare const canisterId: string; diff --git a/frontend/src/declarations/likeFetch/likeFetch.did b/frontend/src/declarations/likeFetch/likeFetch.did index 97a06a2..4ea0a34 100644 --- a/frontend/src/declarations/likeFetch/likeFetch.did +++ b/frontend/src/declarations/likeFetch/likeFetch.did @@ -10,11 +10,11 @@ type PostImmutable = comment: vec Comment; content: text; createdAt: Time; + feedCanister: principal; index: nat; like: vec Like; postId: PostId; repost: vec Repost; - title: text; user: UserId; }; type PostId = text; diff --git a/frontend/src/declarations/likeFetch/likeFetch.did.d.ts b/frontend/src/declarations/likeFetch/likeFetch.did.d.ts index 5f89654..2eb4558 100644 --- a/frontend/src/declarations/likeFetch/likeFetch.did.d.ts +++ b/frontend/src/declarations/likeFetch/likeFetch.did.d.ts @@ -22,13 +22,13 @@ export interface LikeFetch { export type PostId = string; export interface PostImmutable { 'repost' : Array, - 'title' : string, 'content' : string, 'like' : Array, 'createdAt' : Time, 'user' : UserId, 'comment' : Array, 'index' : bigint, + 'feedCanister' : Principal, 'postId' : PostId, } export interface Repost { 'createdAt' : Time, 'user' : UserId } diff --git a/frontend/src/declarations/likeFetch/likeFetch.did.js b/frontend/src/declarations/likeFetch/likeFetch.did.js index 54507d1..63bdd76 100644 --- a/frontend/src/declarations/likeFetch/likeFetch.did.js +++ b/frontend/src/declarations/likeFetch/likeFetch.did.js @@ -11,13 +11,13 @@ export const idlFactory = ({ IDL }) => { const PostId = IDL.Text; const PostImmutable = IDL.Record({ 'repost' : IDL.Vec(Repost), - 'title' : IDL.Text, 'content' : IDL.Text, 'like' : IDL.Vec(Like), 'createdAt' : Time, 'user' : UserId, 'comment' : IDL.Vec(Comment), 'index' : IDL.Nat, + 'feedCanister' : IDL.Principal, 'postId' : PostId, }); const LikeFetch = IDL.Service({ diff --git a/frontend/src/declarations/rootFeed/index.d.ts b/frontend/src/declarations/rootFeed/index.d.ts index b29c33a..662d0ed 100644 --- a/frontend/src/declarations/rootFeed/index.d.ts +++ b/frontend/src/declarations/rootFeed/index.d.ts @@ -7,7 +7,7 @@ import type { import type { Principal } from "@dfinity/principal"; import type { IDL } from "@dfinity/candid"; -import { _SERVICE } from './rootFeed'; +import { _SERVICE } from './rootFeed.did'; export declare const idlFactory: IDL.InterfaceFactory; export declare const canisterId: string; diff --git a/frontend/src/declarations/rootPost/index.d.ts b/frontend/src/declarations/rootPost/index.d.ts index 9df9903..194ffa4 100644 --- a/frontend/src/declarations/rootPost/index.d.ts +++ b/frontend/src/declarations/rootPost/index.d.ts @@ -7,7 +7,7 @@ import type { import type { Principal } from "@dfinity/principal"; import type { IDL } from "@dfinity/candid"; -import { _SERVICE } from './rootPost'; +import { _SERVICE } from './rootPost.did'; export declare const idlFactory: IDL.InterfaceFactory; export declare const canisterId: string; diff --git a/frontend/src/declarations/rootPost/rootPost.did b/frontend/src/declarations/rootPost/rootPost.did index c46cc2c..aba063d 100644 --- a/frontend/src/declarations/rootPost/rootPost.did +++ b/frontend/src/declarations/rootPost/rootPost.did @@ -1,5 +1,6 @@ type RootPost = service { + addAvailBucket: (vec principal) -> (); createBucket: () -> (principal); getAllAvailableBuckets: () -> (vec principal) query; getAllBuckets: () -> (vec principal) query; diff --git a/frontend/src/declarations/rootPost/rootPost.did.js b/frontend/src/declarations/rootPost/rootPost.did.js index 83931a5..a4d82ef 100644 --- a/frontend/src/declarations/rootPost/rootPost.did.js +++ b/frontend/src/declarations/rootPost/rootPost.did.js @@ -1,5 +1,6 @@ export const idlFactory = ({ IDL }) => { const RootPost = IDL.Service({ + 'addAvailBucket' : IDL.Func([IDL.Vec(IDL.Principal)], [], []), 'createBucket' : IDL.Func([], [IDL.Principal], []), 'getAllAvailableBuckets' : IDL.Func( [], diff --git a/frontend/src/declarations/rootPost/rootPost.ts b/frontend/src/declarations/rootPost/rootPost.ts index 69f1f9f..d5b291f 100644 --- a/frontend/src/declarations/rootPost/rootPost.ts +++ b/frontend/src/declarations/rootPost/rootPost.ts @@ -2,6 +2,7 @@ import type { Principal } from '@dfinity/principal'; import type { ActorMethod } from '@dfinity/agent'; export interface RootPost { + 'addAvailBucket' : ActorMethod<[Array], undefined>, 'createBucket' : ActorMethod<[], Principal>, 'getAllAvailableBuckets' : ActorMethod<[], Array>, 'getAllBuckets' : ActorMethod<[], Array>, diff --git a/frontend/src/declarations/user/user.did b/frontend/src/declarations/user/user.did index 4165cee..7c1a1eb 100644 --- a/frontend/src/declarations/user/user.did +++ b/frontend/src/declarations/user/user.did @@ -13,6 +13,7 @@ type User = getProfile: (UserId__1) -> (opt Profile) query; getRootFeedCanister: () -> (principal) query; init: (principal) -> () oneway; + isFollowed: (Vertex, Vertex) -> (bool) query; searchProfile: (text) -> (vec Profile) query; updateProfile: (NewProfile) -> (); }; diff --git a/frontend/src/declarations/user/user.did.js b/frontend/src/declarations/user/user.did.js index fba206a..bd9c211 100644 --- a/frontend/src/declarations/user/user.did.js +++ b/frontend/src/declarations/user/user.did.js @@ -36,6 +36,7 @@ export const idlFactory = ({ IDL }) => { 'getProfile' : IDL.Func([UserId__1], [IDL.Opt(Profile)], ['query']), 'getRootFeedCanister' : IDL.Func([], [IDL.Principal], ['query']), 'init' : IDL.Func([IDL.Principal], [], ['oneway']), + 'isFollowed' : IDL.Func([Vertex, Vertex], [IDL.Bool], ['query']), 'searchProfile' : IDL.Func([IDL.Text], [IDL.Vec(Profile)], ['query']), 'updateProfile' : IDL.Func([NewProfile], [], []), }); diff --git a/frontend/src/declarations/user/user.ts b/frontend/src/declarations/user/user.ts index 23299b1..4166859 100644 --- a/frontend/src/declarations/user/user.ts +++ b/frontend/src/declarations/user/user.ts @@ -31,6 +31,7 @@ export interface User { 'getProfile' : ActorMethod<[UserId__1], [] | [Profile]>, 'getRootFeedCanister' : ActorMethod<[], Principal>, 'init' : ActorMethod<[Principal], undefined>, + 'isFollowed' : ActorMethod<[Vertex, Vertex], boolean>, 'searchProfile' : ActorMethod<[string], Array>, 'updateProfile' : ActorMethod<[NewProfile], undefined>, } diff --git a/frontend/src/routes/profile.tsx b/frontend/src/routes/profile.tsx index 024a6ab..f9b1b47 100644 --- a/frontend/src/routes/profile.tsx +++ b/frontend/src/routes/profile.tsx @@ -1,5 +1,5 @@ import React, {useState, useEffect} from 'react'; -import {Layout, Image, Typography, Avatar, Flex, Space, Button, Modal, message, Spin} from 'antd'; +import {Layout, Image, Typography, Avatar, Flex, Space, Button, Modal, message, notification, Spin} from 'antd'; import Post from '../components/post'; import {userApi} from '../actors/user'; import {Profile} from '../declarations/user/user'; @@ -12,6 +12,8 @@ import {rootFeedApi} from "../actors/rootFeed"; import Feed from "../actors/feed"; import {useAllDataStore, useProfileStore} from "../redux"; import {useAuth} from "../utils/useAuth"; +import { LoadingOutlined, CheckOutlined } from '@ant-design/icons'; + export default function UserProfile() { const {principal: me} = useAuth() @@ -23,6 +25,7 @@ export default function UserProfile() { const [following, setFollowing] = useState(0) const [followers, setFollowers] = useState(0) const [allPosts, setAllPosts] = useState() + const [api, contextHolder] = notification.useNotification(); const {userid} = useParams() const [commentProfiles, setCommentProfiles] = useState() const [commentLoading, setCommentLoading] = useState(true) @@ -99,12 +102,25 @@ export default function UserProfile() { setIsModalOpen(true); }; - const handleClick = async () => { + const handleFollow = async () => { if (isMe) { handleEditProfile() } else { if (!principal) return - userApi.follow(principal).then() + api.info({ + message: 'Follow ing ...', + key: 'follow', + duration: null, + description: '', + icon: + }) + await userApi.follow(principal); + api.success({ + message: 'Follow Successful !', + key: 'follow', + description: '', + icon: + }); } } @@ -143,7 +159,7 @@ export default function UserProfile() { /> {userProfile?.name} - + ; export type PostId = string; export interface PostImmutable { 'repost' : Array, - 'title' : string, 'content' : string, 'like' : Array, 'createdAt' : Time, 'user' : UserId, 'comment' : Array, 'index' : bigint, + 'feedCanister' : Principal, 'postId' : PostId, } export interface Repost { 'createdAt' : Time, 'user' : UserId } diff --git a/src/declarations/bucket/bucket.did.js b/src/declarations/bucket/bucket.did.js index 867d6e4..4f22e23 100644 --- a/src/declarations/bucket/bucket.did.js +++ b/src/declarations/bucket/bucket.did.js @@ -11,13 +11,13 @@ export const idlFactory = ({ IDL }) => { const PostId = IDL.Text; const PostImmutable = IDL.Record({ 'repost' : IDL.Vec(Repost), - 'title' : IDL.Text, 'content' : IDL.Text, 'like' : IDL.Vec(Like), 'createdAt' : Time, 'user' : UserId, 'comment' : IDL.Vec(Comment), 'index' : IDL.Nat, + 'feedCanister' : IDL.Principal, 'postId' : PostId, }); const NewComment = IDL.Vec(Comment); diff --git a/src/declarations/commentFetch/commentFetch.did b/src/declarations/commentFetch/commentFetch.did index 35cc28b..82ed5e1 100644 --- a/src/declarations/commentFetch/commentFetch.did +++ b/src/declarations/commentFetch/commentFetch.did @@ -10,11 +10,11 @@ type PostImmutable = comment: vec Comment; content: text; createdAt: Time; + feedCanister: principal; index: nat; like: vec Like; postId: PostId; repost: vec Repost; - title: text; user: UserId; }; type PostId = text; diff --git a/src/declarations/commentFetch/commentFetch.did.d.ts b/src/declarations/commentFetch/commentFetch.did.d.ts index cf54537..b3bc2a4 100644 --- a/src/declarations/commentFetch/commentFetch.did.d.ts +++ b/src/declarations/commentFetch/commentFetch.did.d.ts @@ -22,13 +22,13 @@ export interface Like { 'createdAt' : Time, 'user' : UserId } export type PostId = string; export interface PostImmutable { 'repost' : Array, - 'title' : string, 'content' : string, 'like' : Array, 'createdAt' : Time, 'user' : UserId, 'comment' : Array, 'index' : bigint, + 'feedCanister' : Principal, 'postId' : PostId, } export interface Repost { 'createdAt' : Time, 'user' : UserId } diff --git a/src/declarations/commentFetch/commentFetch.did.js b/src/declarations/commentFetch/commentFetch.did.js index 9a9b5d2..ad978c4 100644 --- a/src/declarations/commentFetch/commentFetch.did.js +++ b/src/declarations/commentFetch/commentFetch.did.js @@ -11,13 +11,13 @@ export const idlFactory = ({ IDL }) => { const PostId = IDL.Text; const PostImmutable = IDL.Record({ 'repost' : IDL.Vec(Repost), - 'title' : IDL.Text, 'content' : IDL.Text, 'like' : IDL.Vec(Like), 'createdAt' : Time, 'user' : UserId, 'comment' : IDL.Vec(Comment), 'index' : IDL.Nat, + 'feedCanister' : IDL.Principal, 'postId' : PostId, }); const CommentFetch = IDL.Service({ diff --git a/src/declarations/feed/feed.did b/src/declarations/feed/feed.did index d1d5df4..888b9ed 100644 --- a/src/declarations/feed/feed.did +++ b/src/declarations/feed/feed.did @@ -10,11 +10,11 @@ type PostImmutable = comment: vec Comment; content: text; createdAt: Time; + feedCanister: principal; index: nat; like: vec Like; postId: PostId; repost: vec Repost; - title: text; user: UserId; }; type PostId = text; diff --git a/src/declarations/feed/feed.did.d.ts b/src/declarations/feed/feed.did.d.ts index a900014..1d029af 100644 --- a/src/declarations/feed/feed.did.d.ts +++ b/src/declarations/feed/feed.did.d.ts @@ -41,13 +41,13 @@ export interface Like { 'createdAt' : Time, 'user' : UserId } export type PostId = string; export interface PostImmutable { 'repost' : Array, - 'title' : string, 'content' : string, 'like' : Array, 'createdAt' : Time, 'user' : UserId, 'comment' : Array, 'index' : bigint, + 'feedCanister' : Principal, 'postId' : PostId, } export interface Repost { 'createdAt' : Time, 'user' : UserId } diff --git a/src/declarations/feed/feed.did.js b/src/declarations/feed/feed.did.js index bed1396..9b4e76b 100644 --- a/src/declarations/feed/feed.did.js +++ b/src/declarations/feed/feed.did.js @@ -11,13 +11,13 @@ export const idlFactory = ({ IDL }) => { const PostId = IDL.Text; const PostImmutable = IDL.Record({ 'repost' : IDL.Vec(Repost), - 'title' : IDL.Text, 'content' : IDL.Text, 'like' : IDL.Vec(Like), 'createdAt' : Time, 'user' : UserId, 'comment' : IDL.Vec(Comment), 'index' : IDL.Nat, + 'feedCanister' : IDL.Principal, 'postId' : PostId, }); const Feed = IDL.Service({ diff --git a/src/declarations/likeFetch/likeFetch.did b/src/declarations/likeFetch/likeFetch.did index 97a06a2..4ea0a34 100644 --- a/src/declarations/likeFetch/likeFetch.did +++ b/src/declarations/likeFetch/likeFetch.did @@ -10,11 +10,11 @@ type PostImmutable = comment: vec Comment; content: text; createdAt: Time; + feedCanister: principal; index: nat; like: vec Like; postId: PostId; repost: vec Repost; - title: text; user: UserId; }; type PostId = text; diff --git a/src/declarations/likeFetch/likeFetch.did.d.ts b/src/declarations/likeFetch/likeFetch.did.d.ts index 5f89654..2eb4558 100644 --- a/src/declarations/likeFetch/likeFetch.did.d.ts +++ b/src/declarations/likeFetch/likeFetch.did.d.ts @@ -22,13 +22,13 @@ export interface LikeFetch { export type PostId = string; export interface PostImmutable { 'repost' : Array, - 'title' : string, 'content' : string, 'like' : Array, 'createdAt' : Time, 'user' : UserId, 'comment' : Array, 'index' : bigint, + 'feedCanister' : Principal, 'postId' : PostId, } export interface Repost { 'createdAt' : Time, 'user' : UserId } diff --git a/src/declarations/likeFetch/likeFetch.did.js b/src/declarations/likeFetch/likeFetch.did.js index 54507d1..63bdd76 100644 --- a/src/declarations/likeFetch/likeFetch.did.js +++ b/src/declarations/likeFetch/likeFetch.did.js @@ -11,13 +11,13 @@ export const idlFactory = ({ IDL }) => { const PostId = IDL.Text; const PostImmutable = IDL.Record({ 'repost' : IDL.Vec(Repost), - 'title' : IDL.Text, 'content' : IDL.Text, 'like' : IDL.Vec(Like), 'createdAt' : Time, 'user' : UserId, 'comment' : IDL.Vec(Comment), 'index' : IDL.Nat, + 'feedCanister' : IDL.Principal, 'postId' : PostId, }); const LikeFetch = IDL.Service({ diff --git a/src/declarations/rootPost/rootPost.did b/src/declarations/rootPost/rootPost.did index c46cc2c..aba063d 100644 --- a/src/declarations/rootPost/rootPost.did +++ b/src/declarations/rootPost/rootPost.did @@ -1,5 +1,6 @@ type RootPost = service { + addAvailBucket: (vec principal) -> (); createBucket: () -> (principal); getAllAvailableBuckets: () -> (vec principal) query; getAllBuckets: () -> (vec principal) query; diff --git a/src/declarations/rootPost/rootPost.did.d.ts b/src/declarations/rootPost/rootPost.did.d.ts index 69f1f9f..d5b291f 100644 --- a/src/declarations/rootPost/rootPost.did.d.ts +++ b/src/declarations/rootPost/rootPost.did.d.ts @@ -2,6 +2,7 @@ import type { Principal } from '@dfinity/principal'; import type { ActorMethod } from '@dfinity/agent'; export interface RootPost { + 'addAvailBucket' : ActorMethod<[Array], undefined>, 'createBucket' : ActorMethod<[], Principal>, 'getAllAvailableBuckets' : ActorMethod<[], Array>, 'getAllBuckets' : ActorMethod<[], Array>, diff --git a/src/declarations/rootPost/rootPost.did.js b/src/declarations/rootPost/rootPost.did.js index 83931a5..a4d82ef 100644 --- a/src/declarations/rootPost/rootPost.did.js +++ b/src/declarations/rootPost/rootPost.did.js @@ -1,5 +1,6 @@ export const idlFactory = ({ IDL }) => { const RootPost = IDL.Service({ + 'addAvailBucket' : IDL.Func([IDL.Vec(IDL.Principal)], [], []), 'createBucket' : IDL.Func([], [IDL.Principal], []), 'getAllAvailableBuckets' : IDL.Func( [], diff --git a/src/declarations/user/user.did b/src/declarations/user/user.did index 4165cee..7c1a1eb 100644 --- a/src/declarations/user/user.did +++ b/src/declarations/user/user.did @@ -13,6 +13,7 @@ type User = getProfile: (UserId__1) -> (opt Profile) query; getRootFeedCanister: () -> (principal) query; init: (principal) -> () oneway; + isFollowed: (Vertex, Vertex) -> (bool) query; searchProfile: (text) -> (vec Profile) query; updateProfile: (NewProfile) -> (); }; diff --git a/src/declarations/user/user.did.d.ts b/src/declarations/user/user.did.d.ts index 23299b1..4166859 100644 --- a/src/declarations/user/user.did.d.ts +++ b/src/declarations/user/user.did.d.ts @@ -31,6 +31,7 @@ export interface User { 'getProfile' : ActorMethod<[UserId__1], [] | [Profile]>, 'getRootFeedCanister' : ActorMethod<[], Principal>, 'init' : ActorMethod<[Principal], undefined>, + 'isFollowed' : ActorMethod<[Vertex, Vertex], boolean>, 'searchProfile' : ActorMethod<[string], Array>, 'updateProfile' : ActorMethod<[NewProfile], undefined>, } diff --git a/src/declarations/user/user.did.js b/src/declarations/user/user.did.js index fba206a..bd9c211 100644 --- a/src/declarations/user/user.did.js +++ b/src/declarations/user/user.did.js @@ -36,6 +36,7 @@ export const idlFactory = ({ IDL }) => { 'getProfile' : IDL.Func([UserId__1], [IDL.Opt(Profile)], ['query']), 'getRootFeedCanister' : IDL.Func([], [IDL.Principal], ['query']), 'init' : IDL.Func([IDL.Principal], [], ['oneway']), + 'isFollowed' : IDL.Func([Vertex, Vertex], [IDL.Bool], ['query']), 'searchProfile' : IDL.Func([IDL.Text], [IDL.Vec(Profile)], ['query']), 'updateProfile' : IDL.Func([NewProfile], [], []), }); diff --git a/src/feed/database.mo b/src/feed/database.mo index f01e1bf..14650a9 100644 --- a/src/feed/database.mo +++ b/src/feed/database.mo @@ -15,8 +15,11 @@ import Order "mo:base/Order"; import Utils "../utils"; module { - - public class PostDirectory() { + type Post = Types.Post; + public class PostDirectory( + postIndexEntries: Nat, + postMapEntries: [(Nat, Post)] + ) { type Post = Types.Post; type PostImmutable = Types.PostImmutable; @@ -29,20 +32,24 @@ module { type Repost = Types.Repost; type NewRepost = Types.NewRepost; - var postIndex: Nat = 0; - let postMap = TrieMap.TrieMap(Nat.equal, Hash.hash); // postIndex -> Post + var postIndex: Nat = postIndexEntries; + let postMap = TrieMap.fromEntries(postMapEntries.vals(), Nat.equal, Hash.hash); // postIndex -> Post + + public func getPostIndexEntries(): Nat { postIndex }; + + public func getPostMapEntries(): [(Nat, Post)] { Iter.toArray(postMap.entries()) }; private func _getPostId(bucket: Principal, user: Principal, index: Nat): Text { Principal.toText(bucket) # "#" # Principal.toText(user) # "#" # Nat.toText(index) }; // 发帖 - public func createPost(user: UserId, title: Text, content: Text, time: Time, bucket: Principal): PostImmutable { + public func createPost(user: UserId, feedCanister: Principal, content: Text, time: Time, bucket: Principal): PostImmutable { let post: Post = { postId = _getPostId(bucket, user, postIndex); + feedCanister = feedCanister; index = postIndex; user = user; - title = title; content = content; var repost = []; var like = []; @@ -67,10 +74,10 @@ module { case(?post) { return ?{ postId = post.postId; + feedCanister = post.feedCanister; index = post.index; user = post.user; repost = post.repost; - title = post.title; content = post.content; like = post.like; comment = post.comment; @@ -151,12 +158,18 @@ module { }; }; + + type PostImmutable = Types.PostImmutable; - public class FeedDirectory() { + public class FeedDirectory( + feedMapEntries: [(Text, PostImmutable)] + ) { type PostImmutable = Types.PostImmutable; - let feedMap = TrieMap.TrieMap(Text.equal, Text.hash); + let feedMap = TrieMap.fromEntries(feedMapEntries.vals(), Text.equal, Text.hash); + + public func getFeedMapEntries(): [(Text, PostImmutable)] { Iter.toArray(feedMap.entries()) }; public func storeFeed(post: PostImmutable) { feedMap.put(post.postId, post); diff --git a/src/feed/feed.mo b/src/feed/feed.mo index 6671576..5e61e86 100644 --- a/src/feed/feed.mo +++ b/src/feed/feed.mo @@ -84,7 +84,7 @@ actor class Feed( type RootPostActor = Types.RootPostActor; stable var bucket: ?Principal = null; - let rootPostActor: RootPostActor = actor(Principal.toText(rootPostCanister)); + stable let rootPostActor: RootPostActor = actor(Principal.toText(rootPostCanister)); // 更新当前 feed 去存储的 bucket canister public shared func checkAvailableBucket(): async Bool { @@ -105,8 +105,11 @@ actor class Feed( type UserId = Types.UserId; type BucketActor = Types.BucketActor; type PostFetchActor = Types.PostFetchActor; + type Post = Types.Post; - let postDirectory: Database.PostDirectory = Database.PostDirectory(); + stable var postIndexEntries: Nat = 0; + stable var postMapEntries: [(Nat, Post)] = []; + let postDirectory: Database.PostDirectory = Database.PostDirectory(postIndexEntries, postMapEntries); // 查询用户发了多少帖子(统计总数) public query func getPostNumber(): async Nat { @@ -125,7 +128,7 @@ actor class Feed( public shared({caller}) func createPost(title: Text, content: Text): async Text { assert(caller == owner and bucket != null); let _bucket = Option.unwrap(bucket); - let post: PostImmutable = postDirectory.createPost(caller, title, content, Time.now(), _bucket); + let post: PostImmutable = postDirectory.createPost(caller, Principal.fromActor(this), content, Time.now(), _bucket); // 将帖子内容发送给公共区的 Bucket let bucketActor: BucketActor = actor(Principal.toText(_bucket)); @@ -194,7 +197,8 @@ actor class Feed( type CommentFetchActor = Types.CommentFetchActor; type LikeFetchActor = Types.LikeFetchActor; - let feedDirectory = Database.FeedDirectory(); + stable var feedMapEntries: [(Text, PostImmutable)] = []; + let feedDirectory = Database.FeedDirectory(feedMapEntries); public shared({caller}) func receiveFeed(postId: Text): async Bool { let (_bucket, _, _) = Utils.checkPostId(postId); @@ -325,4 +329,14 @@ actor class Feed( feedDirectory.getLatestFeed(n) }; + system func preupgrade() { + postIndexEntries := postDirectory.getPostIndexEntries(); + postMapEntries := postDirectory.getPostMapEntries(); + feedMapEntries := feedDirectory.getFeedMapEntries(); + }; + + system func postupgrade() { + postMapEntries := []; + feedMapEntries := []; + }; } \ No newline at end of file diff --git a/src/feed/rootFeed.mo b/src/feed/rootFeed.mo index a3e8869..a860458 100644 --- a/src/feed/rootFeed.mo +++ b/src/feed/rootFeed.mo @@ -22,7 +22,8 @@ actor class RootFeed( type LikeFetchActor = Types.LikeFetchActor; stable let T_CYCLES = 1_000_000_000_000; - let userFeedCanisterMap = TrieMap.TrieMap(Principal.equal, Principal.hash); + stable var userFeedCanisterMapEntries: [(Principal, Principal)] = []; + let userFeedCanisterMap = TrieMap.fromEntries(userFeedCanisterMapEntries.vals(), Principal.equal, Principal.hash); let ic: IC.Service = actor("aaaaa-aa"); // 给用户创建一个用户自己的 Canister @@ -137,4 +138,13 @@ actor class RootFeed( likeFetchCanister := newLikeFetchCanister; }; + + system func preupgrade() { + userFeedCanisterMapEntries := Iter.toArray(userFeedCanisterMap.entries()); + }; + + system func postupgrade() { + userFeedCanisterMapEntries := []; + }; + } \ No newline at end of file diff --git a/src/fetch/commentFetch.mo b/src/fetch/commentFetch.mo index b687b9e..287d171 100644 --- a/src/fetch/commentFetch.mo +++ b/src/fetch/commentFetch.mo @@ -14,7 +14,8 @@ actor class CommentFetch( type PostImmutable = Types.PostImmutable; type Repost = Types.Repost; - let notifyMap = TrieMap.TrieMap(Principal.equal, Principal.hash); + stable var notifyMapEntries: [(Principal, [Text])] = []; + let notifyMap = TrieMap.fromEntries(notifyMapEntries.vals(), Principal.equal, Principal.hash); public shared({caller}) func receiveNotify(post: PostImmutable): async () { // 查到这个帖子的主用户的 followers @@ -59,7 +60,8 @@ actor class CommentFetch( // userToFeed - var userToFeed = TrieMap.TrieMap(Principal.equal, Principal.hash); + stable var userToFeedEntries: [(Principal, Principal)] = []; + var userToFeed = TrieMap.fromEntries(userToFeedEntries.vals(), Principal.equal, Principal.hash); public shared({caller}) func initUserToFeed(_userToFeedArray: [(Principal, Principal)]): async Bool { userToFeed := TrieMap.fromEntries( @@ -111,4 +113,13 @@ actor class CommentFetch( notify ); -}; \ No newline at end of file + system func preupgrade() { + notifyMapEntries := Iter.toArray(notifyMap.entries()); + userToFeedEntries := Iter.toArray(userToFeed.entries()); + }; + + system func postupgrade() { + notifyMapEntries := []; + userToFeedEntries := []; + }; +}; \ No newline at end of file diff --git a/src/fetch/likeFetch.mo b/src/fetch/likeFetch.mo index 89005a1..5b0f4fe 100644 --- a/src/fetch/likeFetch.mo +++ b/src/fetch/likeFetch.mo @@ -14,7 +14,8 @@ actor class LikeFetch( type PostImmutable = Types.PostImmutable; type Repost = Types.Repost; - let notifyMap = TrieMap.TrieMap(Principal.equal, Principal.hash); + stable var notifyMapEntries: [(Principal, [Text])] = []; + let notifyMap = TrieMap.fromEntries(notifyMapEntries.vals(), Principal.equal, Principal.hash); public shared({caller}) func receiveNotify(post: PostImmutable): async () { // 查到这个帖子的主用户的 followers @@ -59,7 +60,8 @@ actor class LikeFetch( }; // userToFeed - var userToFeed = TrieMap.TrieMap(Principal.equal, Principal.hash); + stable var userToFeedEntries: [(Principal, Principal)] = []; + var userToFeed = TrieMap.fromEntries(userToFeedEntries.vals(), Principal.equal, Principal.hash); public shared({caller}) func initUserToFeed(_userToFeedArray: [(Principal, Principal)]): async Bool { userToFeed := TrieMap.fromEntries( @@ -109,5 +111,15 @@ actor class LikeFetch( #seconds(2), notify ); - + + system func preupgrade() { + notifyMapEntries := Iter.toArray(notifyMap.entries()); + userToFeedEntries := Iter.toArray(userToFeed.entries()); + }; + + system func postupgrade() { + notifyMapEntries := []; + userToFeedEntries := []; + }; + }; \ No newline at end of file diff --git a/src/fetch/postFetch.mo b/src/fetch/postFetch.mo index 03b4285..32ed32d 100644 --- a/src/fetch/postFetch.mo +++ b/src/fetch/postFetch.mo @@ -9,7 +9,8 @@ import Iter "mo:base/Iter"; actor class PostFetch() = this { // 内部维护一个通知表:记录每个用户待通知的帖子 ID 有哪些。 - let notifyMap = TrieMap.TrieMap(Principal.equal, Principal.hash); + stable var notifyMapEntries: [(Principal, [Text])] = []; + let notifyMap = TrieMap.fromEntries(notifyMapEntries.vals(), Principal.equal, Principal.hash); // 接收发帖人的通知:帖子 ID 、发帖人、转发人、followers 、Cycles 。 public shared({caller}) func receiveNotify(to: [Principal], postId: Text): async () { @@ -38,7 +39,8 @@ actor class PostFetch() = this { // userToFeed - var userToFeed = TrieMap.TrieMap(Principal.equal, Principal.hash); + stable var userToFeedEntries: [(Principal, Principal)] = []; + var userToFeed = TrieMap.fromEntries(userToFeedEntries.vals(), Principal.equal, Principal.hash); public shared({caller}) func initUserToFeed(_userToFeedArray: [(Principal, Principal)]): async Bool { userToFeed := TrieMap.fromEntries( @@ -91,5 +93,14 @@ actor class PostFetch() = this { #seconds(2), notify ); - + + system func preupgrade() { + notifyMapEntries := Iter.toArray(notifyMap.entries()); + userToFeedEntries := Iter.toArray(userToFeed.entries()); + }; + + system func postupgrade() { + notifyMapEntries := []; + userToFeedEntries := []; + }; }; \ No newline at end of file diff --git a/src/fetch/rootFetch.mo b/src/fetch/rootFetch.mo index 1a525c6..bb69c35 100644 --- a/src/fetch/rootFetch.mo +++ b/src/fetch/rootFetch.mo @@ -24,9 +24,14 @@ actor class RootFetch( stable var commentFetchCanisterIndex: Nat = 0; stable var likeFetchCanisterIndex: Nat = 0; - let postFetchMap = TrieMap.TrieMap(Nat.equal, Hash.hash); - let commentFetchMap = TrieMap.TrieMap(Nat.equal, Hash.hash); - let likeFetchMap = TrieMap.TrieMap(Nat.equal, Hash.hash); + stable var postFetchMapEntries: [(Nat, Principal)] = []; + let postFetchMap = TrieMap.fromEntries(postFetchMapEntries.vals(), Nat.equal, Hash.hash); + + stable var commentFetchMapEntries: [(Nat, Principal)] = []; + let commentFetchMap = TrieMap.fromEntries(commentFetchMapEntries.vals(), Nat.equal, Hash.hash); + + stable var likeFetchMapEntries: [(Nat, Principal)] = []; + let likeFetchMap = TrieMap.fromEntries(likeFetchMapEntries.vals(), Nat.equal, Hash.hash); public shared({caller}) func init( _rootFeedCanister: Principal, @@ -115,5 +120,16 @@ actor class RootFetch( public query func getAllLikeFetchCanister(): async [Principal] { Iter.toArray(likeFetchMap.vals()) }; - + + system func preupgrade() { + postFetchMapEntries := Iter.toArray(postFetchMap.entries()); + commentFetchMapEntries := Iter.toArray(commentFetchMap.entries()); + likeFetchMapEntries := Iter.toArray(likeFetchMap.entries()); + }; + + system func postupgrade() { + postFetchMapEntries := []; + commentFetchMapEntries := []; + likeFetchMapEntries := []; + }; }; \ No newline at end of file diff --git a/src/post/bucket.mo b/src/post/bucket.mo index 08047f7..5cf74a9 100644 --- a/src/post/bucket.mo +++ b/src/post/bucket.mo @@ -33,7 +33,8 @@ shared(msg) actor class Bucket( stable let installer = msg.caller; // postId -> PostImmutable - let feedMap = TrieMap.TrieMap(Text.equal, Text.hash); + stable var feedMapEntries: [(Text, PostImmutable)] = []; + let feedMap = TrieMap.fromEntries(feedMapEntries.vals(), Text.equal, Text.hash); // 存储帖子 public shared({caller}) func storeFeed(post: PostImmutable): async Bool { @@ -90,10 +91,10 @@ shared(msg) actor class Bucket( case(?post) { let _newPost = { postId = post.postId; + feedCanister = post.feedCanister; index = post.index; user = post.user; repost = post.repost; - title = post.title; content = post.content; like = post.like; comment = newComment; @@ -111,10 +112,10 @@ shared(msg) actor class Bucket( case(?post) { let _newPost = { postId = post.postId; + feedCanister = post.feedCanister; index = post.index; user = post.user; repost = post.repost; - title = post.title; content = post.content; like = newLike; comment = post.comment; @@ -132,9 +133,9 @@ shared(msg) actor class Bucket( case(?post) { feedMap.put(postId, { postId = post.postId; + feedCanister = post.feedCanister; index = post.index; user = post.user; - title = post.title; content = post.content; repost = newRepost; like = post.like; @@ -226,4 +227,11 @@ shared(msg) actor class Bucket( likeFetchCanister := newLikeFetchCanister; }; -}; + system func preupgrade() { + feedMapEntries := Iter.toArray(feedMap.entries()); + }; + + system func postupgrade() { + feedMapEntries := []; + }; +} diff --git a/src/post/rootPost.mo b/src/post/rootPost.mo index be08b2a..7853a4a 100644 --- a/src/post/rootPost.mo +++ b/src/post/rootPost.mo @@ -9,6 +9,7 @@ import Cycles "mo:base/ExperimentalCycles"; import Time "mo:base/Time"; import Int "mo:base/Int"; import Option "mo:base/Option"; +import IC "mo:ic"; actor class RootPost( _commentFetchCanister: Principal, @@ -19,9 +20,14 @@ actor class RootPost( stable let BUCKET_MAX_POST_NUMBER: Nat = 5000; // 每个Bucket可以存储的最大帖子数 (待计算) stable var bucketIndex: Nat = 0; - let buckets = TrieMap.TrieMap(Nat.equal, Hash.hash); - let availableBuckets = TrieMap.TrieMap(Nat.equal, Hash.hash); - let unavailableBuckets = TrieMap.TrieMap(Nat.equal, Hash.hash); + stable var bucketsEntries: [(Nat, Principal)] = []; + let buckets = TrieMap.fromEntries(bucketsEntries.vals(), Nat.equal, Hash.hash); + + stable var availableBucketsEntries: [(Nat, Principal)] = []; + let availableBuckets = TrieMap.fromEntries(availableBucketsEntries.vals(), Nat.equal, Hash.hash); + + stable var unavailableBucketsEntries: [(Nat, Principal)] = []; + let unavailableBuckets = TrieMap.fromEntries(unavailableBucketsEntries.vals(), Nat.equal, Hash.hash); // 开始先创建 5 个 Bucket public shared({caller}) func init(): async () { @@ -44,6 +50,30 @@ actor class RootPost( }; }; + public shared({caller}) func addAvailBucket(bucketArray: [Principal]): async () { + for(_bucket in bucketArray.vals()) { + buckets.put(bucketIndex, _bucket); + availableBuckets.put(bucketIndex, _bucket); + bucketIndex += 1; + }; + }; + + // let ic: IC.Service = actor("aaaaa-aa"); + // public shared({caller}) func updateSettings(bucketArray: [Principal]): async () { + // for(_bucket in bucketArray.vals()) { + // await ic.update_settings({ + // canister_id = _bucket; + // settings = { + // freezing_threshold = null; + // // controllers = ?[Principal.fromActor(this), caller, feedCanisterId]; + // controllers = ?[Principal.fromActor(this), Principal.fromText("fcvlw-g3pmj-ccerf-c4mt2-pwutp-wnwsd-i7c22-dt23k-k3eof-er7nb-5qe")]; + // memory_allocation = null; + // compute_allocation = null; + // } + // }); + // } + // }; + // 创建Bucket public shared({caller}) func createBucket(): async Principal { await _createBucket() @@ -77,6 +107,7 @@ actor class RootPost( // 查询可用的Bucket public query func getAvailableBucket(): async ?Principal { + if(availableBuckets.size() == 0) return null; availableBuckets.get(Nat.rem(Option.unwrap(Nat.fromText(Int.toText(Time.now()))), availableBuckets.size())) }; @@ -120,11 +151,14 @@ actor class RootPost( }; system func preupgrade() { - + bucketsEntries := Iter.toArray(buckets.entries()); + availableBucketsEntries := Iter.toArray(availableBuckets.entries()); + unavailableBucketsEntries := Iter.toArray(unavailableBuckets.entries()); }; system func postupgrade() { - + bucketsEntries := []; + availableBucketsEntries := []; + unavailableBucketsEntries := []; }; - } \ No newline at end of file diff --git a/src/types.mo b/src/types.mo index 8f12dd5..798e3d8 100644 --- a/src/types.mo +++ b/src/types.mo @@ -10,9 +10,9 @@ module { public type Post = { postId: PostId; // 帖子 ID + feedCanister: Principal; index: Nat; // Post Index user: UserId; // 发布者 - title: Text; content: Text; var repost: [Repost]; //转发者 var like: [Like]; @@ -22,9 +22,9 @@ module { public type PostImmutable = { postId: PostId; // 帖子 ID + feedCanister: Principal; index: Nat; // Post Index user: UserId; // 发布者 - title: Text; content: Text; repost: [Repost]; //转发者 like: [Like]; diff --git a/src/user/main.mo b/src/user/main.mo index b9c10b3..6d43563 100644 --- a/src/user/main.mo +++ b/src/user/main.mo @@ -41,6 +41,15 @@ actor class User() = this { graph.addEdge(caller, user); }; + // is userA follow userB + public query({caller}) func isFollowed(userA: Vertex, userB: Vertex): async Bool { + let _followers = graph.getReverseAdjacent(userB); + for(_follower in _followers.vals()) { + if(_follower == userA) return true; + }; + false + }; + public query({caller}) func getFollowingList(user: Vertex): async [Vertex] { graph.getForwardAdjacent(user) }; @@ -95,7 +104,6 @@ actor class User() = this { directory.findBy(term) }; - system func preupgrade() { vertexListEntries := graph.getVertexListEntries(); edgeListEntries := graph.getEdgeListEntries(); diff --git a/src/utils.mo b/src/utils.mo index 50d3a7b..740faae 100644 --- a/src/utils.mo +++ b/src/utils.mo @@ -23,9 +23,9 @@ module { { postId = post.postId; index = post.index; + feedCanister = post.feedCanister; user = post.user; repost = post.repost; - title = post.title; content = post.content; like = post.like; comment = post.comment;