Skip to content

Commit

Permalink
create dao + unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
hughhhh committed Jul 14, 2023
1 parent 767afef commit 4d18262
Show file tree
Hide file tree
Showing 9 changed files with 487 additions and 4 deletions.
1 change: 1 addition & 0 deletions superset-frontend/src/pages/ChartList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ function ChartList(props: ChartListProps) {
chartIds,
addDangerToast,
);

const {
sliceCurrentlyEditing,
handleChartUpdated,
Expand Down
29 changes: 28 additions & 1 deletion superset-frontend/src/pages/Tags/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
createErrorHandler,
Actions,
} from 'src/views/CRUD/utils';
import { useListViewResource } from 'src/views/CRUD/hooks';
import { useListViewResource, useFavoriteStatus } from 'src/views/CRUD/hooks';
import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
import SubMenu, { SubMenuProps } from 'src/features/home/SubMenu';
import ListView, {
Expand All @@ -42,6 +42,7 @@ import { deleteTags } from 'src/features/tags/tags';
import { Tag as AntdTag } from 'antd';
import { Tag } from 'src/views/CRUD/types';
import TagCard from 'src/features/tags/TagCard';
import FaveStar from 'src/components/FaveStar';

const PAGE_SIZE = 25;

Expand Down Expand Up @@ -75,6 +76,13 @@ function TagList(props: TagListProps) {
refreshData,
} = useListViewResource<Tag>('tag', t('tag'), addDangerToast);

const tagIds = useMemo(() => tags.map(c => c.id), [tags]);
const [saveFavoriteStatus, favoriteStatus] = useFavoriteStatus(
'tag',
tagIds,
addDangerToast,
);

// TODO: Fix usage of localStorage keying on the user id
const userKey = dangerouslyGetItemDoNotUse(userId?.toString(), null);

Expand All @@ -94,6 +102,25 @@ function TagList(props: TagListProps) {

const columns = useMemo(
() => [
{
Cell: ({
row: {
original: { id },
},
}: any) =>
userId && (
<FaveStar
itemId={id}
saveFaveStar={saveFavoriteStatus}
isStarred={favoriteStatus[id]}
/>
),
Header: '',
id: 'id',
disableSortBy: true,
size: 'xs',
hidden: !userId,
},
{
Cell: ({
row: {
Expand Down
7 changes: 6 additions & 1 deletion superset-frontend/src/views/CRUD/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -564,10 +564,15 @@ const favoriteApis = {
method: 'GET',
endpoint: '/api/v1/dashboard/favorite_status/',
}),
tag: makeApi<Array<string | number>, FavoriteStatusResponse>({
requestType: 'rison',
method: 'GET',
endpoint: '/api/v1/tag/favorite_status/',
}),
};

export function useFavoriteStatus(
type: 'chart' | 'dashboard',
type: 'chart' | 'dashboard' | 'tag',
ids: Array<string | number>,
handleErrorMsg: (message: string) => void,
) {
Expand Down
98 changes: 97 additions & 1 deletion superset/daos/tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from operator import and_
from typing import Any, Optional

from flask import g
from sqlalchemy.exc import SQLAlchemyError

from superset.daos.base import BaseDAO
Expand All @@ -26,7 +27,15 @@
from superset.models.dashboard import Dashboard
from superset.models.slice import Slice
from superset.models.sql_lab import SavedQuery
from superset.tags.models import get_tag, ObjectTypes, Tag, TaggedObject, TagTypes
from superset.tags.models import (
get_tag,
ObjectTypes,
Tag,
TaggedObject,
TagTypes,
user_favorite_tag_table,
)
from superset.utils.core import get_user_id

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -257,3 +266,90 @@ def get_tagged_objects_for_tags(
for obj in saved_queries
)
return results

@staticmethod
def user_favorite_tag(tag_id: int) -> None:
"""
Marks a specific tag as a favorite for the current user.
This function will find the tag by the provided id,
create a new UserFavoriteTag object that represents
the user's preference, add that object to the database
session, and commit the session. It uses the currently
authenticated user from the global 'g' object.
Args:
tag_id: The id of the tag that is to be marked as
favorite.
Raises:
Any exceptions raised by the find_by_id function,
the UserFavoriteTag constructor, or the database session's
add and commit methods will propagate up to the caller.
Returns:
None.
"""
tag = TagDAO.find_by_id(tag_id)
user = g.user

if tag and user:
tag.users_favorited.append(user)
db.session.add(tag)
db.session.commit()

@staticmethod
def remove_user_favorite_tag(tag_id: int) -> None:
"""
Removes a tag from the current user's favorite tags.
This function will find the tag by the provided id and remove the tag
from the user's list of favorite tags. It uses the currently authenticated
user from the global 'g' object.
Args:
tag_id: The id of the tag that is to be removed from the favorite tags.
Raises:
Any exceptions raised by the find_by_id function, the database session's
commit method will propagate up to the caller.
Returns:
None.
"""
# Find the tag
tag = TagDAO.find_by_id(tag_id)
user = g.user

# Remove the tag from the user's favorites
if tag and user:
tag.users_favorited.remove(user)

# Commit to save the changes
db.session.commit()

@staticmethod
def favorited_ids(tags: list[Tag]) -> list[int]:
"""
Returns the IDs of tags that the current user has favorited.
This function takes in a list of Tag objects, extracts their IDs, and checks
which of these IDs exist in the user_favorite_tag_table for the current user.
The function returns a list of these favorited tag IDs.
Args:
tags (list[Tag]): A list of Tag objects.
Returns:
list[Any]: A list of IDs corresponding to the tags that are favorited by the current user.
Example:
favorited_ids([tag1, tag2, tag3])
Output: [tag_id1, tag_id3] # if the current user has favorited tag1 and tag3
"""
ids = [tag.id for tag in tags]
return [
star.tag_id
for star in db.session.query(user_favorite_tag_table.c.tag_id)
.filter(
user_favorite_tag_table.c.tag_id.in_(ids),
user_favorite_tag_table.c.user_id == get_user_id(),
)
.all()
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""create_user_favorite_table
Revision ID: e0f6f91c2055
Revises: 6d05b0a70c89
Create Date: 2023-07-12 20:34:57.553981
"""

# revision identifiers, used by Alembic.
revision = "e0f6f91c2055"
down_revision = "6d05b0a70c89"

import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"user_favorite_tag",
sa.Column("user_id", sa.Integer(), nullable=True),
sa.Column("tag_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(
["tag_id"],
["tag.id"],
),
sa.ForeignKeyConstraint(
["user_id"],
["ab_user.id"],
),
)
# ### end Alembic commands ###


def downgrade():
op.drop_table("user_favorite_tag")
Loading

0 comments on commit 4d18262

Please sign in to comment.