add following/follower

pull/51/head
sunface 4 years ago
parent f6fc6ddc84
commit 6bb93c579e

@ -1,4 +1,4 @@
import { Box, chakra, Flex, HStack, VStack, Image, Heading, Text, Button, useColorModeValue, Divider, Wrap, Avatar, Center } from "@chakra-ui/react"
import { Box, chakra, Flex, HStack, VStack, Image, Heading, Text, Button, useColorModeValue, Divider, Wrap, Avatar, Center, useDisclosure, Modal, ModalOverlay, ModalContent, ModalCloseButton, ModalBody, StackDivider, Stack, ModalHeader } from "@chakra-ui/react"
import Card from "components/card"
import Container from "components/container"
import SEO from "components/seo"
@ -7,7 +7,7 @@ import useSession from "hooks/use-session"
import PageContainer1 from "layouts/page-container1"
import { useRouter } from "next/router"
import React, { useEffect, useState } from "react"
import {FaFacebook, FaFile, FaGithub, FaHeart, FaPlus, FaRegStar, FaStackOverflow, FaStar, FaTwitter, FaWeibo, FaZhihu } from "react-icons/fa"
import { FaFacebook, FaFile, FaGithub, FaHeart, FaPlus, FaRegStar, FaStackOverflow, FaStar, FaTwitter, FaWeibo, FaZhihu } from "react-icons/fa"
import { ReserveUrls } from "src/data/reserve-urls"
import { User } from "src/types/user"
import { requestApi } from "utils/axios/request"
@ -18,22 +18,27 @@ import Link from "next/link"
import Empty from "components/empty"
import Count from "components/count"
import { Tag } from "src/types/tag"
import { IDType } from "src/types/id"
import UserCard from "components/users/user-card"
import userCustomTheme from "theme/user-custom"
const UserPage = () => {
const { isOpen, onOpen, onClose } = useDisclosure()
const router = useRouter()
const username = router.query.username
const session = useSession()
const [user, setUser]: [User, any] = useState(null)
const [rawPosts, setRawPosts]: [Story[], any] = useState([])
const [posts, setPosts]: [Story[], any] = useState([])
const [tags,setTags]:[Tag[],any] = useState([])
const [tagFilter,setTagFilter]:[Tag,any] = useState(null)
const [tags, setTags]: [Tag[], any] = useState([])
const [tagFilter, setTagFilter]: [Tag, any] = useState(null)
const [followers, setFollowers]: [User[], any] = useState([])
const borderColor = useColorModeValue('white', 'transparent')
const stackBorderColor = useColorModeValue(userCustomTheme.borderColor.light, userCustomTheme.borderColor.dark)
useEffect(() => {
if (username) {
initData(username)
}
}, [username])
const initData = async (username) => {
@ -41,7 +46,7 @@ const UserPage = () => {
setUser(res.data)
getTags(res.data.id)
const res1 = await requestApi.get(`/user/posts/${res.data.id}`)
setPosts(res1.data)
setRawPosts(res1.data)
@ -56,16 +61,16 @@ const UserPage = () => {
if (tag.id === tagFilter?.id) {
setTagFilter(null)
setPosts(rawPosts)
return
return
}
setTagFilter(tag)
const p = []
rawPosts.forEach(post => {
for (let i=0;i<post.rawTags.length;i++) {
for (let i = 0; i < post.rawTags.length; i++) {
if (post.rawTags[i].id === tag.id) {
p.push(post)
break
p.push(post)
break
}
}
})
@ -73,6 +78,28 @@ const UserPage = () => {
setPosts(p)
}
const viewFollowers = async tp => {
let res
if (tp === 1) {
// followings
const res0 = await requestApi.get(`/interaction/following/${user.id}?type=${IDType.User}`)
const ids = []
for (const f of res0.data) {
ids.push(f.id)
}
res = await requestApi.post(`/user/ids`, ids)
} else {
// followers
res = await requestApi.get(`/interaction/followers/${user.id}?type=${IDType.User}`)
}
setFollowers(res.data)
if (res.data.length > 0) {
onOpen()
}
}
return (
<>
<SEO
@ -90,21 +117,23 @@ const UserPage = () => {
<Heading size="lg">{user.nickname}</Heading>
{user.tagline && <Text layerStyle="textSecondary" fontWeight="450" fontSize="1.2rem" ml="1" mt="2">{user.tagline}</Text>}
<Flex layerStyle="textSecondary" spacing="2" pt="1" alignItems="center">
<chakra.span><FaHeart /></chakra.span><chakra.span ml="1">Followers <chakra.a fontWeight="600"><Count count={user.follows}/></chakra.a></chakra.span>
<chakra.span ml="5"><FaStar /></chakra.span><chakra.span ml="1">Following <chakra.a fontWeight="600"><Count count={0}/></chakra.a></chakra.span>
{/* <chakra.span><FaHeart /></chakra.span> */}
<chakra.span cursor="pointer" onClick={() => viewFollowers(0)}>Followers <chakra.a fontWeight="600"><Count count={user.follows} /></chakra.a></chakra.span>
{/* <chakra.span ml="5"><FaStar /></chakra.span> */}
<chakra.span ml="3" cursor="pointer" onClick={() => viewFollowers(1)}>Following <chakra.a fontWeight="600"><Count count={user.followings??0} /></chakra.a></chakra.span>
</Flex>
<Box pt="3" position="absolute" right="15px" top="60px">{session?.user.id === user.id ? <Button onClick={() => router.push(`${ReserveUrls.Settings}/profile`)} variant="outline" leftIcon={<svg height="1.3rem" fill="currentColor" viewBox="0 0 512 512"><path d="M493.255 56.236l-37.49-37.49c-24.993-24.993-65.515-24.994-90.51 0L12.838 371.162.151 485.346c-1.698 15.286 11.22 28.203 26.504 26.504l114.184-12.687 352.417-352.417c24.992-24.994 24.992-65.517-.001-90.51zm-95.196 140.45L174 420.745V386h-48v-48H91.255l224.059-224.059 82.745 82.745zM126.147 468.598l-58.995 6.555-30.305-30.305 6.555-58.995L63.255 366H98v48h48v34.745l-19.853 19.853zm344.48-344.48l-49.941 49.941-82.745-82.745 49.941-49.941c12.505-12.505 32.748-12.507 45.255 0l37.49 37.49c12.506 12.506 12.507 32.747 0 45.255z"></path></svg>}><chakra.span display={{base:"none",md:"block"}}>Edit Profile</chakra.span></Button>
<Box pt="3" position="absolute" right="15px" top="60px">{session?.user.id === user.id ? <Button onClick={() => router.push(`${ReserveUrls.Settings}/profile`)} variant="outline" leftIcon={<svg height="1.3rem" fill="currentColor" viewBox="0 0 512 512"><path d="M493.255 56.236l-37.49-37.49c-24.993-24.993-65.515-24.994-90.51 0L12.838 371.162.151 485.346c-1.698 15.286 11.22 28.203 26.504 26.504l114.184-12.687 352.417-352.417c24.992-24.994 24.992-65.517-.001-90.51zm-95.196 140.45L174 420.745V386h-48v-48H91.255l224.059-224.059 82.745 82.745zM126.147 468.598l-58.995 6.555-30.305-30.305 6.555-58.995L63.255 366H98v48h48v34.745l-19.853 19.853zm344.48-344.48l-49.941 49.941-82.745-82.745 49.941-49.941c12.505-12.505 32.748-12.507 45.255 0l37.49 37.49c12.506 12.506 12.507 32.747 0 45.255z"></path></svg>}><chakra.span display={{ base: "none", md: "block" }}>Edit Profile</chakra.span></Button>
: <Button colorScheme="teal">Follow</Button>}</Box>
</VStack>
</Card>
<HStack spacing={[0, 0, 4, 4]} mt="4" alignItems="top">
<VStack alignItems="left" spacing="4" width="350px" display={{ base: "none", md: "flex" }}>
<Card>
{user.about &&
<>
<Text layerStyle="textSecondary">{user.about}</Text>
<Divider my="4" />
</>}
{user.about &&
<>
<Text layerStyle="textSecondary">{user.about}</Text>
<Divider my="4" />
</>}
{user.location && <HStack>
<chakra.span layerStyle="textSecondary" width="90px">Location: </chakra.span>
<chakra.span fontWeight="500" ml="2">{user.location}</chakra.span>
@ -120,7 +149,7 @@ const UserPage = () => {
<chakra.span fontWeight="500" ml="2">{moment(user.created).fromNow()}</chakra.span>
</HStack>
<HStack layerStyle="textSecondary" fontSize="1.4rem" mt={(user.github || user.twitter || user.facebook || user.stackoverflow || user.weibo || user.zhihu) ? 4 : 0 } spacing="5">
<HStack layerStyle="textSecondary" fontSize="1.4rem" mt={(user.github || user.twitter || user.facebook || user.stackoverflow || user.weibo || user.zhihu) ? 4 : 0} spacing="5">
{user.github && <chakra.a href={user.github} target="_blank"><FaGithub /></chakra.a>}
{user.twitter && <chakra.a href={user.twitter} target="_blank"><FaTwitter /></chakra.a>}
{user.facebook && <chakra.a href={user.facebook} target="_blank"><FaFacebook /></chakra.a>}
@ -128,14 +157,14 @@ const UserPage = () => {
{user.zhihu && <chakra.a href={user.zhihu} target="_blank"><FaZhihu /></chakra.a>}
{user.weibo && <chakra.a href={user.weibo} target="_blank"><FaWeibo /></chakra.a>}
</HStack>
{user.availFor && <Box>
<Divider my="4" />
<Text fontWeight="600" layerStyle="textSecondary">I am available for</Text>
<Text mt="2">{user.availFor}</Text>
</Box>}
</Card>
{user.rawSkills.length > 0 && <Card>
{user.rawSkills?.length > 0 && <Card>
<Heading size="sm" layerStyle="textSecondary" fontWeight="500"></Heading>
<Wrap mt="4" p="1">
{
@ -145,7 +174,7 @@ const UserPage = () => {
<Avatar src={skill.icon} size="sm" />
<Text>{skill.title}</Text>
</HStack>
</Link>)
</Link>)
}
</Wrap>
</Card>}
@ -156,7 +185,7 @@ const UserPage = () => {
{
tags.map(tag =>
<Button size="sm" variant="ghost" p="0" onClick={() => filterPostsByTag(tag)} _focus={null}>
<Box className={tagFilter?.id === tag.id ? "tag-bg" : null} py="2" px="3">{tag.name} &nbsp; {tag.posts}</Box>
<Box className={tagFilter?.id === tag.id ? "tag-bg" : null} py="2" px="3">{tag.name} &nbsp; {tag.posts}</Box>
</Button>
)
}
@ -165,23 +194,36 @@ const UserPage = () => {
</VStack>
<Box width={["100%","100%","70%","70%"]}>
{ posts.length === 0 ?
<Box width={["100%", "100%", "70%", "70%"]}>
{posts.length === 0 ?
<Card width="100%" height="fit-content">
<Empty />
</Card>
:
<Card width="100%" height="fit-content" p="0" px="3">
<Stories stories={posts} showFooter={tagFilter === null}/>
<Stories stories={posts} showFooter={tagFilter === null} />
</Card>
}
</Box>
}
</Box>
</HStack>
</Box>
}
<Modal isOpen={isOpen} onClose={onClose} size="xl" isCentered>
<ModalOverlay />
<ModalContent mt="0">
<ModalBody maxHeight="calc(100vh - 200px)" overflowY="scroll" >
<VStack alignItems="left" divider={<StackDivider borderColor={stackBorderColor} />} >
{followers.map(user =>
<UserCard user={user} />
)}
</VStack>
</ModalBody>
</ModalContent>
</Modal>
</PageContainer1>
</>
)

@ -1,79 +0,0 @@
import {Text, Box, Heading, Image, Center, Button, Flex, VStack, Divider, useToast } from "@chakra-ui/react"
import Card from "components/card"
import Nav from "layouts/nav/nav"
import PageContainer from "layouts/page-container"
import Sidebar from "layouts/sidebar/sidebar"
import React, { useEffect, useState } from "react"
import {adminLinks, followLinks} from "src/data/links"
import { requestApi } from "utils/axios/request"
import TagCard from "components/tags/tag-card"
import { useRouter } from "next/router"
import Link from "next/link"
import { ReserveUrls } from "src/data/reserve-urls"
import { Tag } from "src/types/tag"
import { route } from "next/dist/next-server/server/router"
import PageContainer1 from "layouts/page-container1"
import Empty from "components/empty"
const FollowersPage = () => {
const [tags, setTags] = useState([])
const router = useRouter()
const toast = useToast()
const getTags = () => {
requestApi.get(`/tag/all`).then((res) => setTags(res.data)).catch(_ => setTags([]))
}
useEffect(() => {
getTags()
}, [])
const editTag = (tag: Tag) => {
router.push(`${ReserveUrls.Admin}/tag/${tag.name}`)
}
const deleteTag= async (id) => {
await requestApi.delete(`/tag/${id}`)
getTags()
toast({
description: "删除成功",
status: "success",
duration: 2000,
isClosable: true,
})
}
return (
<>
<PageContainer1>
<Box display="flex">
<Sidebar routes={followLinks} title="我的关注" />
<Card ml="4" p="6" width="100%">
<Flex alignItems="center" justify="space-between">
<Heading size="md">({tags.length})</Heading>
<Button colorScheme="teal" size="sm" _focus={null}><Link href={`${ReserveUrls.Admin}/tag/new`}></Link></Button>
</Flex>
{
tags.length === 0 ?
<Empty />
:
<>
<VStack mt="4">
{tags.map(tag =>
<Box width="100%" key={tag.id}>
<TagCard tag={tag} showActions={true} mt="4" onEdit={() => editTag(tag)} onDelete={() => deleteTag(tag.id)} />
<Divider mt="5" />
</Box>
)}
</VStack>
<Center><Text layerStyle="textSecondary" fontSize="sm" mt="5"></Text></Center>
</>
}
</Card>
</Box>
</PageContainer1>
</>
)
}
export default FollowersPage

@ -1,79 +0,0 @@
import {Text, Box, Heading, Image, Center, Button, Flex, VStack, Divider, useToast } from "@chakra-ui/react"
import Card from "components/card"
import Nav from "layouts/nav/nav"
import PageContainer from "layouts/page-container"
import Sidebar from "layouts/sidebar/sidebar"
import React, { useEffect, useState } from "react"
import {adminLinks, followLinks} from "src/data/links"
import { requestApi } from "utils/axios/request"
import TagCard from "components/tags/tag-card"
import { useRouter } from "next/router"
import Link from "next/link"
import { ReserveUrls } from "src/data/reserve-urls"
import { Tag } from "src/types/tag"
import { route } from "next/dist/next-server/server/router"
import PageContainer1 from "layouts/page-container1"
import Empty from "components/empty"
const UsersPage = () => {
const [tags, setTags] = useState([])
const router = useRouter()
const toast = useToast()
const getTags = () => {
requestApi.get(`/tag/all`).then((res) => setTags(res.data)).catch(_ => setTags([]))
}
useEffect(() => {
getTags()
}, [])
const editTag = (tag: Tag) => {
router.push(`${ReserveUrls.Admin}/tag/${tag.name}`)
}
const deleteTag= async (id) => {
await requestApi.delete(`/tag/${id}`)
getTags()
toast({
description: "删除成功",
status: "success",
duration: 2000,
isClosable: true,
})
}
return (
<>
<PageContainer1>
<Box display="flex">
<Sidebar routes={followLinks} title="我的关注" />
<Card ml="4" p="6" width="100%">
<Flex alignItems="center" justify="space-between">
<Heading size="md">({tags.length})</Heading>
<Button colorScheme="teal" size="sm" _focus={null}><Link href={`${ReserveUrls.Admin}/tag/new`}></Link></Button>
</Flex>
{
tags.length === 0 ?
<Empty />
:
<>
<VStack mt="4">
{tags.map(tag =>
<Box width="100%" key={tag.id}>
<TagCard tag={tag} showActions={true} mt="4" onEdit={() => editTag(tag)} onDelete={() => deleteTag(tag.id)} />
<Divider mt="5" />
</Box>
)}
</VStack>
<Center><Text layerStyle="textSecondary" fontSize="sm" mt="5"></Text></Center>
</>
}
</Card>
</Box>
</PageContainer1>
</>
)
}
export default UsersPage

@ -0,0 +1,52 @@
import {Text, Box, Heading, Image, Center, Button, Flex, VStack, Divider, useToast, Wrap, WrapItem, useColorModeValue, StackDivider } from "@chakra-ui/react"
import Card from "components/card"
import Nav from "layouts/nav/nav"
import PageContainer from "layouts/page-container"
import Sidebar from "layouts/sidebar/sidebar"
import React, { useEffect, useState } from "react"
import {adminLinks, interactionLinks} from "src/data/links"
import { requestApi } from "utils/axios/request"
import PageContainer1 from "layouts/page-container1"
import Empty from "components/empty"
import { IDType } from "src/types/id"
import UserCard from "components/users/user-card"
import userCustomTheme from "theme/user-custom"
const FollowersPage = () => {
const [users, setUsers] = useState([])
const borderColor = useColorModeValue(userCustomTheme.borderColor.light, userCustomTheme.borderColor.dark)
const getUsers = async () => {
const res = await requestApi.get(`/interaction/followers/0?type=${IDType.User}`)
setUsers(res.data)
}
useEffect(() => {
getUsers()
}, [])
return (
<>
<PageContainer1>
<Box display="flex">
<Sidebar routes={interactionLinks} title="我的关注" />
<Card ml="4" p="6" width="100%">
{
users.length === 0 ? <Empty /> :
<VStack alignItems="left" divider={<StackDivider borderColor={borderColor} />} >
{users.map(user =>
<UserCard user={user} />
)}
</VStack>
}
</Card>
</Box>
</PageContainer1>
</>
)
}
export default FollowersPage

@ -2,7 +2,7 @@ import { Text, Box, Heading, Image, Divider, useToast, HStack, Slider, SliderTra
import Card from "components/card"
import Sidebar from "layouts/sidebar/sidebar"
import React, { useEffect, useState } from "react"
import { followLinks } from "src/data/links"
import {interactionLinks} from "src/data/links"
import { requestApi } from "utils/axios/request"
import { useRouter } from "next/router"
import PageContainer1 from "layouts/page-container1"
@ -42,7 +42,7 @@ const TagsPage = () => {
<>
<PageContainer1>
<Box display="flex">
<Sidebar routes={followLinks} title="我的关注" />
<Sidebar routes={interactionLinks} title="我的关注" />
<Card ml="4" p="6" width="100%">
<Text fontSize=".95rem" fontWeight="600">Adjust tag weight to modify your home feed. Higher values mean more appearances.</Text>
<Divider my="6" />

@ -0,0 +1,59 @@
import {Text, Box, Heading, Image, Center, Button, Flex, VStack, Divider, useToast, Wrap, WrapItem, useColorModeValue, StackDivider } from "@chakra-ui/react"
import Card from "components/card"
import Nav from "layouts/nav/nav"
import PageContainer from "layouts/page-container"
import Sidebar from "layouts/sidebar/sidebar"
import React, { useEffect, useState } from "react"
import {interactionLinks} from "src/data/links"
import { requestApi } from "utils/axios/request"
import PageContainer1 from "layouts/page-container1"
import Empty from "components/empty"
import { IDType } from "src/types/id"
import UserCard from "components/users/user-card"
import userCustomTheme from "theme/user-custom"
const UsersPage = () => {
const [users, setUsers] = useState([])
const borderColor = useColorModeValue(userCustomTheme.borderColor.light, userCustomTheme.borderColor.dark)
const getUsers = async () => {
const res = await requestApi.get(`/interaction/following/0?type=${IDType.User}`)
const ids = []
for (const f of res.data) {
ids.push(f.id)
}
const res1 = await requestApi.post(`/user/ids`, ids)
setUsers(res1.data)
}
useEffect(() => {
getUsers()
}, [])
return (
<>
<PageContainer1>
<Box display="flex">
<Sidebar routes={interactionLinks} title="我的关注" />
<Card ml="4" p="6" width="100%">
{
users.length === 0 ? <Empty /> :
<VStack alignItems="left" divider={<StackDivider borderColor={borderColor} />} >
{users.map(user =>
<UserCard user={user} />
)}
</VStack>
}
</Card>
</Box>
</PageContainer1>
</>
)
}
export default UsersPage

@ -74,13 +74,35 @@ func GetFollowing(c *gin.Context) {
userID = u.ID
}
tags, err := interaction.GetFollowing(userID, targetType)
following, err := interaction.GetFollowing(userID, targetType)
if err != nil {
c.JSON(err.Status, common.RespError(err.Message))
return
}
c.JSON(http.StatusOK, common.RespSuccess(tags))
c.JSON(http.StatusOK, common.RespSuccess(following))
}
func GetFollowers(c *gin.Context) {
userID := c.Param("userID")
targetType := c.Query("type")
if userID == "" || !models.ValidFollowIDType(targetType) {
c.JSON(http.StatusBadRequest, common.RespError(e.ParamInvalid))
return
}
if userID == "0" {
u := user.CurrentUser(c)
userID = u.ID
}
followers, err := interaction.GetFollowers(userID, targetType)
if err != nil {
c.JSON(err.Status, common.RespError(err.Message))
return
}
c.JSON(http.StatusOK, common.RespSuccess(followers))
}
func SetFollowingWeight(c *gin.Context) {

@ -21,6 +21,19 @@ func GetUsers(c *gin.Context) {
c.JSON(http.StatusOK, common.RespSuccess(users))
}
func GetUsersByIDs(c *gin.Context) {
ids := make([]string, 0)
err := c.Bind(&ids)
if err != nil {
c.JSON(http.StatusBadRequest, common.RespError(e.ParamInvalid))
return
}
us := user.GetUsersByIDs(ids)
c.JSON(http.StatusOK, common.RespSuccess(us))
}
func GetUserSelf(c *gin.Context) {
u := user.CurrentUser(c)

@ -10,13 +10,12 @@ import (
)
var logger = log.RootLogger.New("logger", "cache")
var Users []*models.User
func Init() {
time.Sleep(10 * time.Second)
time.Sleep(2 * time.Second)
for {
// load users
rows, err := db.Conn.Query(`SELECT id,username,role,nickname,email,avatar,last_seen_at,created FROM user`)
rows, err := db.Conn.Query(`SELECT id,username,role,nickname,avatar,last_seen_at,created FROM user`)
if err != nil {
logger.Error("load users error", "error", err)
time.Sleep(60 * time.Second)
@ -24,9 +23,10 @@ func Init() {
}
var users []*models.User
usersMap := make(map[string]*models.User)
for rows.Next() {
user := &models.User{}
err := rows.Scan(&user.ID, &user.Username, &user.Role, &user.Nickname, &user.Email, &user.Avatar, &user.LastSeenAt, &user.Created)
err := rows.Scan(&user.ID, &user.Username, &user.Role, &user.Nickname, &user.Avatar, &user.LastSeenAt, &user.Created)
if err != nil {
logger.Warn("scan user error", "error", err)
continue
@ -43,9 +43,11 @@ func Init() {
user.Follows = interaction.GetFollows(user.ID)
users = append(users, user)
usersMap[user.ID] = user
}
Users = users
models.UsersCache = users
models.UsersMapCache = usersMap
time.Sleep(60 * time.Second)
}

@ -93,6 +93,16 @@ func GetFollows(targetID string) int {
return follows
}
func GetFollowings(userID string, targetType string) int {
var followings int
err := db.Conn.QueryRow("SELECT count(*) FROM follows WHERE user_id=? and target_type=?", userID, targetType).Scan(&followings)
if err != nil && err != sql.ErrNoRows {
logger.Warn("get following count error", "error", err)
}
return followings
}
func GetFollowing(userID, targetType string) ([]*models.Following, *e.Error) {
rows, err := db.Conn.Query("SELECT target_id,weight from follows where user_id=? and target_type=?", userID, targetType)
if err != nil {
@ -111,6 +121,28 @@ func GetFollowing(userID, targetType string) ([]*models.Following, *e.Error) {
return following, nil
}
func GetFollowers(targetID, targetType string) ([]*models.User, *e.Error) {
rows, err := db.Conn.Query("SELECT user_id from follows where target_id=? and target_type=? ORDER BY created DESC", targetID, targetType)
if err != nil {
logger.Warn("get followers error", "error", err)
return nil, e.New(http.StatusInternalServerError, e.Internal)
}
users := make([]*models.User, 0)
for rows.Next() {
var id string
rows.Scan(&id)
u, ok := models.UsersMapCache[id]
if ok {
users = append(users, u)
u.Followed = GetFollowed(u.ID, targetID)
}
}
return users, nil
}
func SetFolloingWeight(userID string, f *models.Following) *e.Error {
_, err := db.Conn.Exec("UPDATE follows SET weight=? WHERE user_id=? and target_id=?", f.Weight, userID, f.ID)
if err != nil {

@ -4,7 +4,6 @@ import (
"sort"
"strings"
"github.com/imdotdev/im.dev/server/internal/cache"
"github.com/imdotdev/im.dev/server/internal/interaction"
"github.com/imdotdev/im.dev/server/internal/story"
"github.com/imdotdev/im.dev/server/pkg/db"
@ -39,10 +38,8 @@ func Posts(user *models.User, filter, query string) []*models.Story {
}
func Users(user *models.User, filter, query string) []*models.User {
allUsers := cache.Users
users := make(models.Users, 0)
for _, u := range allUsers {
for _, u := range models.UsersCache {
if strings.Contains(strings.ToLower(u.Nickname), strings.ToLower(query)) {
users = append(users, u)
continue

@ -75,6 +75,7 @@ func (s *Server) Start() error {
r.GET("/tag/user/:userID", api.GetUserTags)
// user apis
r.GET("/user/all", api.GetUsers)
r.POST("/user/ids", api.GetUsersByIDs)
r.GET("/user/self", IsLogin(), api.GetUserSelf)
r.GET("/user/info/:username", api.GetUser)
r.POST("/user/update", IsLogin(), api.UpdateUser)
@ -89,6 +90,7 @@ func (s *Server) Start() error {
r.POST("/interaction/following/weight", IsLogin(), api.SetFollowingWeight)
r.GET("/interaction/followed/:id", api.Followed)
r.GET("/interaction/following/:userID", api.GetFollowing)
r.GET("/interaction/followers/:userID", api.GetFollowers)
// search apis
r.GET("/search/posts/:filter", api.SearchPosts)

@ -6,7 +6,6 @@ import (
"strings"
"time"
"github.com/imdotdev/im.dev/server/internal/cache"
"github.com/imdotdev/im.dev/server/internal/interaction"
"github.com/imdotdev/im.dev/server/internal/tags"
"github.com/imdotdev/im.dev/server/pkg/db"
@ -15,10 +14,8 @@ import (
)
func GetUsers(q string) ([]*models.User, *e.Error) {
allUsers := cache.Users
users := make([]*models.User, 0)
for _, u := range allUsers {
for _, u := range models.UsersCache {
if strings.HasPrefix(strings.ToLower(u.Nickname), strings.ToLower(q)) {
users = append(users, u)
continue
@ -33,6 +30,19 @@ func GetUsers(q string) ([]*models.User, *e.Error) {
return users, nil
}
func GetUsersByIDs(ids []string) []*models.User {
users := make([]*models.User, 0)
for _, id := range ids {
u, ok := models.UsersMapCache[id]
if ok {
users = append(users, u)
}
u.Followed = true
}
return users
}
func GetUserDetail(id string, username string) (*models.User, *e.Error) {
user := &models.User{}
err := user.Query(id, username, "")
@ -65,6 +75,8 @@ func GetUserDetail(id string, username string) (*models.User, *e.Error) {
user.Follows = interaction.GetFollows(user.ID)
user.Followings = interaction.GetFollowings(user.ID, models.IDTypeUser)
return user, nil
}

@ -4,7 +4,7 @@ package common
var ReserverURLs = []string{
"/tags",
"/courses",
"/follow",
"/interaction",
"/editor",
"/admin",
"/bookmarks",

@ -0,0 +1,4 @@
package models
var UsersCache []*User
var UsersMapCache map[string]*User

@ -11,27 +11,28 @@ type User struct {
Username string `json:"username"`
Nickname string `json:"nickname"`
Avatar string `json:"avatar"`
Email string `json:"email"`
Role RoleType `json:"role"`
Tagline string `json:"tagline"`
Cover string `json:"cover"`
Location string `json:"location"`
AvailFor string `json:"availFor"`
About string `json:"about"`
RawSkills []*Tag `json:"rawSkills"`
Skills []string `json:"skills"`
Website string `json:"website"`
Twitter string `json:"twitter"`
Github string `json:"github"`
Zhihu string `json:"zhihu"`
Weibo string `json:"weibo"`
Facebook string `json:"facebook"`
Stackoverflow string `json:"stackoverflow"`
Follows int `json:"follows"`
Followed bool `json:"followed"`
Email string `json:"email,omitempty"`
Role RoleType `json:"role,omitempty"`
Tagline string `json:"tagline,omitempty"`
Cover string `json:"cover,omitempty"`
Location string `json:"location,omitempty"`
AvailFor string `json:"availFor,omitempty"`
About string `json:"about,omitempty"`
RawSkills []*Tag `json:"rawSkills,omitempty"`
Skills []string `json:"skills,omitempty"`
Website string `json:"website,omitempty"`
Twitter string `json:"twitter,omitempty"`
Github string `json:"github,omitempty"`
Zhihu string `json:"zhihu,omitempty"`
Weibo string `json:"weibo,omitempty"`
Facebook string `json:"facebook,omitempty"`
Stackoverflow string `json:"stackoverflow,omitempty"`
Follows int `json:"follows,omitempty"`
Followings int `json:"followings,omitempty"`
Followed bool `json:"followed,omitempty"`
LastSeenAt time.Time `json:"lastSeenAt,omitempty"`
Created time.Time `json:"created"`

@ -14,6 +14,7 @@ export const Card = ({shadowed, ...rest}: BoxProps&Props) => {
borderWidth="1px"
p={[2,2,4,4]}
boxShadow={shadowed? "0 1px 1px 0 rgb(0 0 0 / 5%)" : null}
height="fit-content"
{...rest}
/>
)

@ -57,7 +57,7 @@ export const UserMenu = () => {
<MenuDivider />
{isEditor(session.user.role) && <Link href={`${ReserveUrls.Editor}/posts`}><MenuItem icon={<FaEdit fontSize="16" />} ></MenuItem></Link>}
<Link href={`${ReserveUrls.Bookmarks}`}><MenuItem icon={<FaBookmark fontSize="16" />}></MenuItem></Link>
<Link href={`${ReserveUrls.Follow}/tags`}><MenuItem icon={<FaHeart fontSize="16" />}></MenuItem></Link>
<Link href={`${ReserveUrls.Interaction}/following-tags`}><MenuItem icon={<FaHeart fontSize="16" />}></MenuItem></Link>
{isAdmin(session.user.role) && <Link href={`${ReserveUrls.Admin}/tags`}><MenuItem icon={<FaStar fontSize="16" />} ></MenuItem></Link>}
<MenuDivider />
<Link href={`${ReserveUrls.Settings}/profile`}><MenuItem icon={<FaRegSun fontSize="16" />}></MenuItem></Link>

@ -7,6 +7,7 @@ import { User } from "src/types/user"
import { getUserName } from "utils/user"
import Follow from "components/interaction/follow"
import Highlighter from 'react-highlight-words';
import Count from "components/count"
type Props = PropsOf<typeof chakra.div> & {
user : User
@ -45,7 +46,7 @@ export const UserCard= ({user,highlight}:Props) =>{
</VStack>
</HStack>
<HStack>
<Text fontWeight="600" fontSize=".9rem">{user.follows} followers</Text>
<Text fontWeight="600" fontSize=".9rem"><Count count={user.follows??0}/> followers</Text>
<Follow followed={user.followed} targetID={user.id} size="sm"/>
</HStack>

@ -24,20 +24,20 @@ export const editorLinks: Route[] = [{
}
]
export const followLinks: any[] = [
export const interactionLinks: any[] = [
{
title: 'Following tags',
path: `${ReserveUrls.Follow}/tags`,
path: `${ReserveUrls.Interaction}/following-tags`,
disabled: false
},
{
title: 'Following users',
path: `${ReserveUrls.Follow}/users`,
path: `${ReserveUrls.Interaction}/following-users`,
disabled: false
},
{
title: 'Followers',
path: `${ReserveUrls.Follow}/followers`,
path: `${ReserveUrls.Interaction}/followers`,
disabled: false
},
]

@ -2,7 +2,7 @@
export enum ReserveUrls {
Tags = "/tags",
Courses = "/courses",
Follow = "/follow",
Interaction = "/interaction",
Editor = "/editor",
Admin = "/admin",
Bookmarks = "/bookmarks",

@ -32,7 +32,8 @@ export interface User {
facebook?: string
stackoverflow?: string
follows?: number
follows?: number
followings?: number
followed?: boolean
lastSeenAt?: string

Loading…
Cancel
Save