Skip to content

Release 0.30.1 #2018

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,6 @@ storybook-static/

/**/.yarn/cache
.swc

# ignore local ssl certs
certs/
8 changes: 8 additions & 0 deletions RELEASE.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
Release Notes
=============

Version 0.30.1
--------------

- Remove imports for builtin django User model (#2012)
- track additional browse events in posthog (#2011)
- Update dependency faker to v35 (#1996)
- Fix support for hardware accelerated embedding generation via ollama (#2008)

Version 0.30.0 (Released February 06, 2025)
--------------

Expand Down
15 changes: 11 additions & 4 deletions channels/api.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
"""API for channels"""

from django.contrib.auth.models import Group, User
from typing import TYPE_CHECKING

from django.contrib.auth.models import Group
from django.db import transaction

from channels.constants import CHANNEL_ROLE_CHOICES, CHANNEL_ROLE_MODERATORS
from channels.models import Channel, ChannelGroupRole

if TYPE_CHECKING:
from django.contrib.auth import get_user_model

User = get_user_model()


def create_channel_groups_and_roles(
channel: Channel,
Expand All @@ -31,14 +38,14 @@ def get_role_model(channel: Channel, role: str) -> ChannelGroupRole:
return ChannelGroupRole.objects.get(channel=channel, role=role)


def add_user_role(channel: Channel, role: str, user: User):
def add_user_role(channel: Channel, role: str, user: "User"):
"""
Add a user to a channel role's group
"""
get_role_model(channel, role).group.user_set.add(user)


def remove_user_role(channel: Channel, role: str, user: User):
def remove_user_role(channel: Channel, role: str, user: "User"):
"""
Remove a user from a channel role's group
"""
Expand All @@ -51,7 +58,7 @@ def get_group_role_name(channel_id: int, role: str) -> str:
return f"channel_{channel_name}_{role}"


def is_moderator(user: User, channel_id: int) -> bool:
def is_moderator(user: "User", channel_id: int) -> bool:
"""
Determine if the user is a moderator for a channel (or a staff user)
"""
Expand Down
6 changes: 5 additions & 1 deletion channels/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import logging

from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
from django.db.models import Prefetch
from django.utils.decorators import method_decorator
from django_filters.rest_framework import DjangoFilterBackend
Expand Down Expand Up @@ -169,6 +169,8 @@ def get_queryset(self):
"""
Build a queryset of relevant users with moderator permissions for this channel
"""
User = get_user_model()

channel_group_name = get_group_role_name(
self.kwargs["id"],
CHANNEL_ROLE_MODERATORS,
Expand All @@ -190,6 +192,8 @@ class ChannelModeratorDetailView(APIView):

def delete(self, request, *args, **kwargs): # noqa: ARG002
"""Remove the user from the moderator groups for this website"""
User = get_user_model()

user = User.objects.get(username=self.kwargs["moderator_name"])
remove_user_role(
Channel.objects.get(id=self.kwargs["id"]), CHANNEL_ROLE_MODERATORS, user
Expand Down
5 changes: 4 additions & 1 deletion channels/views_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from math import ceil

import pytest
from django.contrib.auth.models import Group, User
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.urls import reverse

from channels.api import add_user_role
Expand All @@ -26,6 +27,8 @@

pytestmark = pytest.mark.django_db

User = get_user_model()


def test_list_channels(user_client):
"""Test that all channels are returned"""
Expand Down
6 changes: 3 additions & 3 deletions docs/how-to/embeddings.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,17 @@ To get setup:

```
QDRANT_ENCODER=vector_search.encoders.litellm.LiteLLMEncoder
LITELLM_API_BASE=http://docker.for.mac.host.internal:11434
LITELLM_API_BASE=http://docker.for.mac.host.internal:11434/v1/
QDRANT_DENSE_MODEL=<ollama model name>
```

_Note_ - "LITELLM_API_BASE=http://docker.for.mac.host.internal:11434" is Mac specific - if you are using another OS you will need to figure out what your host machine's docker address is.
_Note_ - "LITELLM_API_BASE=http://docker.for.mac.host.internal:11434/v1/" is Mac specific - if you are using another OS you will need to figure out what your host machine's docker address is.

Sample .env file configuration on Mac:

```
QDRANT_ENCODER=vector_search.encoders.litellm.LiteLLMEncoder
LITELLM_API_BASE=http://docker.for.mac.host.internal:11434
LITELLM_API_BASE=http://docker.for.mac.host.internal:11434/v1/
QDRANT_DENSE_MODEL=all-minilm
```

Expand Down
28 changes: 13 additions & 15 deletions frontends/main/src/app-pages/ChannelPage/TopicChannelTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { propsNotNil, backgroundSrcSetCSS } from "ol-utilities"
import invariant from "tiny-invariant"
import backgroundSteps from "@/public/images/backgrounds/background_steps.jpg"
import { usePostHog } from "posthog-js/react"
import { PostHogEvents } from "@/common/constants"

const ChildrenContainer = styled.div(({ theme }) => ({
paddingTop: "40px",
Expand Down Expand Up @@ -79,14 +80,18 @@ const BannerSkeleton = styled(Skeleton)(({ theme }) => ({
}))

type TopicChipsInternalProps = {
title: string
topicId: number
parentTopicId: number
isTopLevelTopic: boolean
}

const TopicChipsInternal: React.FC<TopicChipsInternalProps> = (props) => {
const posthog = usePostHog()
const { title, topicId, parentTopicId } = props
const { topicId, parentTopicId, isTopLevelTopic } = props
const title = isTopLevelTopic ? "Subtopics" : "Related Topics"
const posthogEvent = isTopLevelTopic
? PostHogEvents.SubTopicClicked
: PostHogEvents.RelatedTopicClicked
const subTopicsQuery = useLearningResourceTopics({
parent_topic_id: [parentTopicId],
})
Expand All @@ -106,7 +111,7 @@ const TopicChipsInternal: React.FC<TopicChipsInternalProps> = (props) => {
href={topic.channel_url ?? ""}
onClick={() => {
if (process.env.NEXT_PUBLIC_POSTHOG_API_KEY) {
posthog.capture("related_topic_link_clicked", { topic })
posthog.capture(posthogEvent, { topic })
}
}}
label={topic.name}
Expand All @@ -127,24 +132,17 @@ const TopicChips: React.FC<TopicChipsProps> = (props) => {
return null
}
const isTopLevelTopic = topic?.parent === null
const parentTopicId = isTopLevelTopic ? topic.id : topic?.parent

if (isTopLevelTopic) {
if (parentTopicId) {
return (
<TopicChipsInternal
title="Subtopics"
topicId={topic.id}
parentTopicId={topic.id}
parentTopicId={parentTopicId}
isTopLevelTopic={isTopLevelTopic}
/>
)
} else if (topic?.parent) {
return (
<TopicChipsInternal
title="Related Topics"
topicId={topic.id}
parentTopicId={topic?.parent}
/>
)
} else return null
}
}

type SubTopicBreadcrumbsProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import backgroundSteps from "@/public/images/backgrounds/background_steps.jpg"
import { aggregateProgramCounts, aggregateCourseCounts } from "@/common/utils"
import { useChannelCounts } from "api/hooks/channels"
import { usePostHog } from "posthog-js/react"
import { PostHogEvents } from "@/common/constants"

const SCHOOL_ICONS: Record<string, React.ReactNode> = {
// School of Architecture and Planning
Expand Down Expand Up @@ -155,7 +156,9 @@ const SchoolDepartments: React.FC<SchoolDepartmentProps> = ({
new URL(department.channel_url).pathname
}
onClick={() => {
posthog.capture("department_link_clicked", { department })
posthog.capture(PostHogEvents.DepartmentLinkClicked, {
department,
})
}}
>
<ListItemText
Expand Down
21 changes: 20 additions & 1 deletion frontends/main/src/app-pages/HomePage/BrowseTopicsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { ButtonLink } from "@mitodl/smoot-design"
import { useLearningResourceTopics } from "api/hooks/learningResources"
import { RiArrowRightLine } from "@remixicon/react"
import RootTopicIcon from "@/components/RootTopicIcon/RootTopicIcon"
import { usePostHog } from "posthog-js/react"
import { PostHogEvents } from "@/common/constants"

const Section = styled.section`
background: #fff url("/images/backgrounds/open-bg-texture-with-gradient.svg")
Expand Down Expand Up @@ -104,6 +106,7 @@ const SeeAllButton = styled(ButtonLink)`
`

const BrowseTopicsSection: React.FC = () => {
const posthog = usePostHog()
const { data: topics } = useLearningResourceTopics({ is_toplevel: true })

return (
Expand All @@ -119,6 +122,13 @@ const BrowseTopicsSection: React.FC = () => {
<TopicBox
key={id}
href={channelUrl ? new URL(channelUrl!).pathname : ""}
onClick={() => {
if (process.env.NEXT_PUBLIC_POSTHOG_API_KEY) {
posthog.capture(PostHogEvents.HomeTopicClicked, {
topic: name,
})
}
}}
>
<TopicBoxContent>
<RootTopicIcon icon={icon} />
Expand All @@ -130,7 +140,16 @@ const BrowseTopicsSection: React.FC = () => {
},
)}
</Topics>
<SeeAllButton href="/topics/" size="large" responsive>
<SeeAllButton
href="/topics/"
onClick={() => {
if (process.env.NEXT_PUBLIC_POSTHOG_API_KEY) {
posthog.capture(PostHogEvents.HomeSeeAllTopicsClicked)
}
}}
size="large"
responsive
>
See all
</SeeAllButton>
</Container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ import { aggregateProgramCounts, aggregateCourseCounts } from "@/common/utils"
import { useChannelCounts } from "api/hooks/channels"
import backgroundSteps from "@/public/images/backgrounds/background_steps.jpg"
import { usePostHog } from "posthog-js/react"
import type { PostHog } from "posthog-js"
import { PostHogEvents } from "@/common/constants"

const captureTopicClicked = (
posthog: PostHog,
event: string,
topic: string,
) => {
if (process.env.NEXT_PUBLIC_POSTHOG_API_KEY) {
posthog.capture(event, { topic })
}
}

type ChannelSummary = {
id: number | string
Expand All @@ -37,12 +49,20 @@ type TopicBoxHeaderProps = {
icon?: string
href?: string
className?: string
posthog?: PostHog
}
const TopicBoxHeader = styled(
({ title, icon, href, className }: TopicBoxHeaderProps) => {
({ title, icon, href, className, posthog }: TopicBoxHeaderProps) => {
return (
<Typography variant="h5" component="h2" className={className}>
<Link href={href ?? ""}>
<Link
href={href ?? ""}
onClick={() => {
if (posthog) {
captureTopicClicked(posthog, PostHogEvents.TopicClicked, title)
}
}}
>
<RootTopicIcon icon={icon} aria-hidden="true" />
<span>
<span className="topic-title">{title}</span>
Expand Down Expand Up @@ -131,15 +151,10 @@ const TopicBox = ({
{ label: "Programs", count: programCount },
].filter((item) => item.count)
const { title, href, icon, channels } = topicGroup
const captureTopicClicked = (topic: string) => {
if (process.env.NEXT_PUBLIC_POSTHOG_API_KEY) {
posthog.capture("topic_clicked", { topic })
}
}

return (
<li className={className}>
<TopicBoxHeader title={title} href={href} icon={icon} />
<TopicBoxHeader title={title} href={href} icon={icon} posthog={posthog} />
<TopicBoxBody>
<TopicCounts>
{counts.map((item) => (
Expand All @@ -156,7 +171,11 @@ const TopicBox = ({
key={c.id}
href={c.channel_url && new URL(c.channel_url).pathname}
onClick={() => {
captureTopicClicked(title)
captureTopicClicked(
posthog,
PostHogEvents.SubTopicClicked,
c.name,
)
}}
label={c.name}
/>
Expand All @@ -170,7 +189,11 @@ const TopicBox = ({
key={c.id}
href={c.channel_url && new URL(c.channel_url).pathname}
onClick={() => {
captureTopicClicked(title)
captureTopicClicked(
posthog,
PostHogEvents.SubTopicClicked,
c.name,
)
}}
label={c.name}
/>
Expand Down
5 changes: 4 additions & 1 deletion frontends/main/src/app-pages/UnitsListingPage/UnitCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from "ol-components"
import Link from "next/link"
import { usePostHog } from "posthog-js/react"
import { PostHogEvents } from "@/common/constants"

const CardStyled = styled(Card)({
height: "100%",
Expand Down Expand Up @@ -132,7 +133,9 @@ const UnitCard: React.FC<UnitCardProps> = (props) => {
href={href}
onClick={() => {
if (process.env.NEXT_PUBLIC_POSTHOG_API_KEY) {
posthog.capture("provider_link_clicked", { provider: unit })
posthog.capture(PostHogEvents.ProviderLinkClicked, {
provider: unit,
})
}
}}
data-card-link
Expand Down
Loading
Loading