From 831a336690f96a6470560a590d7dd5e57f1d8129 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Fri, 14 Jun 2024 17:37:05 +0530 Subject: [PATCH 1/5] [WEB-1613] chore: material logo loader (#4823) * chore: material logo loader added * chore: material logo loader added --- packages/ui/package.json | 3 +- packages/ui/src/emoji/icons-list.tsx | 35 +++++++++++++------ web/core/components/common/logo.tsx | 21 +++++++++++ web/package.json | 1 + yarn.lock | 52 +++++++++------------------- 5 files changed, 66 insertions(+), 46 deletions(-) diff --git a/packages/ui/package.json b/packages/ui/package.json index 49a1e4443..0914e18fd 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -34,7 +34,8 @@ "react-dom": "^18.2.0", "react-popper": "^2.3.0", "sonner": "^1.4.41", - "tailwind-merge": "^2.0.0" + "tailwind-merge": "^2.0.0", + "use-font-face-observer": "^1.2.2" }, "devDependencies": { "@chromatic-com/storybook": "^1.4.0", diff --git a/packages/ui/src/emoji/icons-list.tsx b/packages/ui/src/emoji/icons-list.tsx index 0352e1ec8..6575ae8f0 100644 --- a/packages/ui/src/emoji/icons-list.tsx +++ b/packages/ui/src/emoji/icons-list.tsx @@ -1,13 +1,15 @@ import React, { useEffect, useState } from "react"; +// icons +import { Search } from "lucide-react"; +import { MATERIAL_ICONS_LIST } from "./icons"; +import { InfoIcon } from "../icons"; // components import { Input } from "../form-fields"; +// hooks +import useFontFaceObserver from "use-font-face-observer"; // helpers import { cn } from "../../helpers"; import { DEFAULT_COLORS, TIconsListProps, adjustColorForContrast } from "./emoji-icon-helper"; -// icons -import { MATERIAL_ICONS_LIST } from "./icons"; -import { InfoIcon } from "../icons"; -import { Search } from "lucide-react"; export const IconsList: React.FC = (props) => { const { defaultColor, onChange } = props; @@ -28,6 +30,15 @@ export const IconsList: React.FC = (props) => { const filteredArray = MATERIAL_ICONS_LIST.filter((icon) => icon.name.toLowerCase().includes(query.toLowerCase())); + const isMaterialSymbolsFontLoaded = useFontFaceObserver([ + { + family: `Material Symbols Rounded`, + style: `normal`, + weight: `normal`, + stretch: `condensed`, + }, + ]); + return ( <>
@@ -118,12 +129,16 @@ export const IconsList: React.FC = (props) => { }); }} > - - {icon.name} - + {isMaterialSymbolsFontLoaded ? ( + + {icon.name} + + ) : ( + + )} ))}
diff --git a/web/core/components/common/logo.tsx b/web/core/components/common/logo.tsx index b2c0b3d39..52d3dedb9 100644 --- a/web/core/components/common/logo.tsx +++ b/web/core/components/common/logo.tsx @@ -4,6 +4,7 @@ import { FC } from "react"; // emoji-picker-react import { Emoji } from "emoji-picker-react"; // import { icons } from "lucide-react"; +import useFontFaceObserver from "use-font-face-observer"; import { TLogoProps } from "@plane/types"; // helpers import { LUCIDE_ICONS_LIST } from "@plane/ui"; @@ -26,9 +27,29 @@ export const Logo: FC = (props) => { const color = icon?.color; const lucideIcon = LUCIDE_ICONS_LIST.find((item) => item.name === value); + const isMaterialSymbolsFontLoaded = useFontFaceObserver([ + { + family: `Material Symbols Rounded`, + style: `normal`, + weight: `normal`, + stretch: `condensed`, + }, + ]); // if no value, return empty fragment if (!value) return <>; + if (!isMaterialSymbolsFontLoaded) { + return ( + + ); + } + // emoji if (in_use === "emoji") { return ; diff --git a/web/package.json b/web/package.json index 068867902..f6b82b4ec 100644 --- a/web/package.json +++ b/web/package.json @@ -62,6 +62,7 @@ "swr": "^2.1.3", "tailwind-merge": "^2.0.0", "use-debounce": "^9.0.4", + "use-font-face-observer": "^1.2.2", "uuid": "^9.0.0", "zxcvbn": "^4.4.2" }, diff --git a/yarn.lock b/yarn.lock index 11a57223c..edda62dcd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4453,7 +4453,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@18.2.48", "@types/react@^16.8.0 || ^17.0.0 || ^18.0.0", "@types/react@^18.2.42", "@types/react@^18.2.48": +"@types/react@*", "@types/react@^16.8.0 || ^17.0.0 || ^18.0.0", "@types/react@^18.2.42", "@types/react@^18.2.48": version "18.2.48" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.48.tgz#11df5664642d0bd879c1f58bc1d37205b064e8f1" integrity sha512-qboRCl6Ie70DQQG9hhNREz81jqC1cs9EVNcjQ1AU+jH6NFfSAhVVbrrY/+nSF+Bsk4AOwm9Qa61InvMCyV+H3w== @@ -7714,6 +7714,11 @@ follow-redirects@^1.15.6: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== +fontfaceobserver@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fontfaceobserver/-/fontfaceobserver-2.1.0.tgz#e2705d293e2c585a6531c2a722905657317a2991" + integrity sha512-ReOsO2F66jUa0jmv2nlM/s1MiutJx/srhAe2+TE8dJCMi02ZZOcCTxTCQFr3Yet+uODUtnr4Mewg+tNQ+4V1Ng== + for-each@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -10831,7 +10836,7 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -"prettier-fallback@npm:prettier@^3": +"prettier-fallback@npm:prettier@^3", prettier@^3.1.1, prettier@^3.2.5, prettier@latest: version "3.3.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.1.tgz#e68935518dd90bb7ec4821ba970e68f8de16e1ac" integrity sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg== @@ -10858,11 +10863,6 @@ prettier@^2.8.8: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== -prettier@^3.1.1, prettier@^3.2.5, prettier@latest: - version "3.3.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.1.tgz#e68935518dd90bb7ec4821ba970e68f8de16e1ac" - integrity sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg== - pretty-bytes@^5.3.0, pretty-bytes@^5.4.1: version "5.6.0" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" @@ -12294,16 +12294,7 @@ string-argv@~0.3.2: resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -12399,14 +12390,7 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -13417,6 +13401,13 @@ use-debounce@^9.0.4: resolved "https://registry.yarnpkg.com/use-debounce/-/use-debounce-9.0.4.tgz#51d25d856fbdfeb537553972ce3943b897f1ac85" integrity sha512-6X8H/mikbrt0XE8e+JXRtZ8yYVvKkdYRfmIhWZYsP8rcNs9hk3APV8Ua2mFkKRLcJKVdnX2/Vwrmg2GWKUQEaQ== +use-font-face-observer@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/use-font-face-observer/-/use-font-face-observer-1.2.2.tgz#ed230d907589c6b17e8c8b896c9f5913968ac5ed" + integrity sha512-5C11YC9vPQn5TeIKDvHHiUg59FBzV1LDIOjYJ2PVgn1raVoKHcuWf3dxVDb7OiqQVg3M2S1jX3LxbLw16xo8gg== + dependencies: + fontfaceobserver "2.1.0" + use-sidecar@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2" @@ -13897,16 +13888,7 @@ workbox-window@6.6.1, workbox-window@^6.5.4: "@types/trusted-types" "^2.0.2" workbox-core "6.6.1" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== From 2a740b9cd9701e18db705ff36a7bf18cc983873d Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Fri, 14 Jun 2024 17:40:33 +0530 Subject: [PATCH 2/5] [WEB - 1604]fix: pagination on many to many fields when grouping and sub grouping (#4818) * fix: pagination on module grouping * fix: pagination on grouping with m2m fields --- apiserver/plane/utils/paginator.py | 61 +++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/apiserver/plane/utils/paginator.py b/apiserver/plane/utils/paginator.py index 8bea4746a..3ea74bf9b 100644 --- a/apiserver/plane/utils/paginator.py +++ b/apiserver/plane/utils/paginator.py @@ -187,11 +187,11 @@ class OffsetPaginator: class GroupedOffsetPaginator(OffsetPaginator): - # Field mappers + # Field mappers - list m2m fields here FIELD_MAPPER = { "labels__id": "label_ids", "assignees__id": "assignee_ids", - "modules__id": "module_ids", + "issue_module__module_id": "module_ids", } def __init__( @@ -205,8 +205,12 @@ class GroupedOffsetPaginator(OffsetPaginator): ): # Initiate the parent class for all the parameters super().__init__(queryset, *args, **kwargs) + + # Set the group by field name self.group_by_field_name = group_by_field_name + # Set the group by fields self.group_by_fields = group_by_fields + # Set the count filter - this are extra filters that need to be passed to calculate the counts with the filters self.count_filter = count_filter def get_result(self, limit=50, cursor=None): @@ -224,8 +228,11 @@ class GroupedOffsetPaginator(OffsetPaginator): offset = cursor.offset * cursor.value stop = offset + (cursor.value or limit) + 1 + # Check if the offset is greater than the max offset if self.max_offset is not None and offset >= self.max_offset: raise BadPaginationError("Pagination offset too large") + + # Check if the offset is less than 0 if offset < 0: raise BadPaginationError("Pagination offset cannot be negative") @@ -269,6 +276,8 @@ class GroupedOffsetPaginator(OffsetPaginator): False, queryset.filter(row_number__gte=stop).exists(), ) + + # Add previous cursors prev_cursor = Cursor( limit, page - 1, @@ -305,7 +314,7 @@ class GroupedOffsetPaginator(OffsetPaginator): ) def __get_total_queryset(self): - # Get total queryset + # Get total items for each group return ( self.queryset.values(self.group_by_field_name) .annotate( @@ -328,7 +337,6 @@ class GroupedOffsetPaginator(OffsetPaginator): ) + (1 if group.get("count") == 0 else group.get("count")) ) - return total_group_dict def __get_field_dict(self): @@ -353,7 +361,7 @@ class GroupedOffsetPaginator(OffsetPaginator): # Grouping for m2m values total_group_dict = self.__get_total_dict() - # Preparing a dict to keep track of group IDs associated with each label ID + # Preparing a dict to keep track of group IDs associated with each entity ID result_group_mapping = defaultdict(set) # Preparing a dict to group result by group ID grouped_by_field_name = defaultdict(list) @@ -390,7 +398,7 @@ class GroupedOffsetPaginator(OffsetPaginator): return processed_results def __query_grouper(self, results): - # Grouping for single values + # Grouping for values that are not m2m processed_results = self.__get_field_dict() for result in results: group_value = str(result.get(self.group_by_field_name)) @@ -411,10 +419,11 @@ class GroupedOffsetPaginator(OffsetPaginator): class SubGroupedOffsetPaginator(OffsetPaginator): + # Field mappers this are the fields that are m2m FIELD_MAPPER = { "labels__id": "label_ids", "assignees__id": "assignee_ids", - "modules__id": "module_ids", + "issue_module__module_id": "module_ids", } def __init__( @@ -428,11 +437,18 @@ class SubGroupedOffsetPaginator(OffsetPaginator): *args, **kwargs, ): + # Initiate the parent class for all the parameters super().__init__(queryset, *args, **kwargs) + + # Set the group by field name self.group_by_field_name = group_by_field_name self.group_by_fields = group_by_fields + + # Set the sub group by field name self.sub_group_by_field_name = sub_group_by_field_name self.sub_group_by_fields = sub_group_by_fields + + # Set the count filter - this are extra filters that need to be passed to calculate the counts with the filters self.count_filter = count_filter def get_result(self, limit=30, cursor=None): @@ -441,13 +457,19 @@ class SubGroupedOffsetPaginator(OffsetPaginator): if cursor is None: cursor = Cursor(0, 0, 0) + # get the minimum value limit = min(limit, self.max_limit) # Adjust the initial offset and stop based on the cursor and limit queryset = self.queryset + # the current page page = cursor.offset + + # the offset offset = cursor.offset * cursor.value + + # the stop stop = offset + (cursor.value or limit) + 1 if self.max_offset is not None and offset >= self.max_offset: @@ -496,6 +518,8 @@ class SubGroupedOffsetPaginator(OffsetPaginator): False, queryset.filter(row_number__gte=stop).exists(), ) + + # Add previous cursors prev_cursor = Cursor( limit, page - 1, @@ -579,19 +603,24 @@ class SubGroupedOffsetPaginator(OffsetPaginator): subgroup = str(item[self.sub_group_by_field_name]) count = item["count"] + # Create a dictionary of group and sub group if group not in total_sub_group_dict: total_sub_group_dict[str(group)] = {} + # Create a dictionary of sub group if subgroup not in total_sub_group_dict[group]: total_sub_group_dict[str(group)][str(subgroup)] = {} + # Create a nested dictionary of group and sub group total_sub_group_dict[group][subgroup] = count return total_group_dict, total_sub_group_dict def __get_field_dict(self): + # Create a field dictionary total_group_dict, total_sub_group_dict = self.__get_total_dict() + # Create a dictionary of group and sub group return { str(group): { "results": { @@ -621,7 +650,6 @@ class SubGroupedOffsetPaginator(OffsetPaginator): result_id = result["id"] group_id = result[self.group_by_field_name] result_group_mapping[str(result_id)].add(str(group_id)) - # Use the same calculation for the sub group if self.sub_group_by_field_name in self.FIELD_MAPPER: for result in results: @@ -635,6 +663,9 @@ class SubGroupedOffsetPaginator(OffsetPaginator): group_value = str(result.get(self.group_by_field_name)) # Get the sub group value sub_group_value = str(result.get(self.sub_group_by_field_name)) + # Check if the group value is in the processed results + result_id = result["id"] + if ( group_value in processed_results and sub_group_value @@ -647,12 +678,14 @@ class SubGroupedOffsetPaginator(OffsetPaginator): [] if "None" in group_ids else group_ids ) if self.sub_group_by_field_name in self.FIELD_MAPPER: - sub_group_ids = list(result_group_mapping[str(result_id)]) - # for multi groups - result[self.FIELD_MAPPER.get(self.group_by_field_name)] = ( - [] if "None" in sub_group_ids else sub_group_ids + sub_group_ids = list( + result_sub_group_mapping[str(result_id)] ) - + # for multi groups + result[ + self.FIELD_MAPPER.get(self.sub_group_by_field_name) + ] = ([] if "None" in sub_group_ids else sub_group_ids) + # If a result belongs to multiple groups, add it to each group processed_results[str(group_value)]["results"][ str(sub_group_value) ]["results"].append(result) @@ -677,8 +710,10 @@ class SubGroupedOffsetPaginator(OffsetPaginator): self.group_by_field_name in self.FIELD_MAPPER or self.sub_group_by_field_name in self.FIELD_MAPPER ): + # if the grouping is done through m2m then processed_results = self.__query_multi_grouper(results=results) else: + # group it directly processed_results = self.__query_grouper(results=results) else: processed_results = {} From 59256588db52214cf9825153dde443014d59e773 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Fri, 14 Jun 2024 17:42:50 +0530 Subject: [PATCH 3/5] [WEB-1628] style: fix admin app telmetry checkbox on setup page. (#4824) --- admin/components/instance/setup-form.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/admin/components/instance/setup-form.tsx b/admin/components/instance/setup-form.tsx index 77bf8e562..aa2350894 100644 --- a/admin/components/instance/setup-form.tsx +++ b/admin/components/instance/setup-form.tsx @@ -319,6 +319,8 @@ export const InstanceSetupForm: FC = (props) => {
handleFormChange("is_telemetry_enabled", !formData.is_telemetry_enabled)} checked={formData.is_telemetry_enabled} From 5bbb796e5e682fae92f6bb6322e6f26b7e74bf94 Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Fri, 14 Jun 2024 17:59:45 +0530 Subject: [PATCH 4/5] fix: migration order --- ...ider_and_more.py => 0069_alter_account_provider_and_more.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename apiserver/plane/db/migrations/{0067_alter_account_provider_and_more.py => 0069_alter_account_provider_and_more.py} (89%) diff --git a/apiserver/plane/db/migrations/0067_alter_account_provider_and_more.py b/apiserver/plane/db/migrations/0069_alter_account_provider_and_more.py similarity index 89% rename from apiserver/plane/db/migrations/0067_alter_account_provider_and_more.py rename to apiserver/plane/db/migrations/0069_alter_account_provider_and_more.py index c8f7571f2..309f73d04 100644 --- a/apiserver/plane/db/migrations/0067_alter_account_provider_and_more.py +++ b/apiserver/plane/db/migrations/0069_alter_account_provider_and_more.py @@ -6,7 +6,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('db', '0066_account_id_token_cycle_logo_props_module_logo_props'), + ('db', '0068_remove_pagelabel_project_remove_pagelog_project_and_more'), ] operations = [ From 84236f506b0b22d337492c1994abc855a1081c21 Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Fri, 14 Jun 2024 18:29:12 +0530 Subject: [PATCH 5/5] fix: gitlab authentication (#4826) --- .../authentication/provider/oauth/gitlab.py | 69 ++++++++----------- 1 file changed, 28 insertions(+), 41 deletions(-) diff --git a/apiserver/plane/authentication/provider/oauth/gitlab.py b/apiserver/plane/authentication/provider/oauth/gitlab.py index a251e5f8b..3795cc37f 100644 --- a/apiserver/plane/authentication/provider/oauth/gitlab.py +++ b/apiserver/plane/authentication/provider/oauth/gitlab.py @@ -16,49 +16,37 @@ from plane.authentication.adapter.error import ( class GitLabOAuthProvider(OauthAdapter): - (GITLAB_HOST,) = get_configuration_value( - [ - { - "key": "GITLAB_HOST", - "default": os.environ.get("GITLAB_HOST", "https://gitlab.com"), - }, - ] - ) - - if not GITLAB_HOST: - raise AuthenticationException( - error_code=AUTHENTICATION_ERROR_CODES["GITLAB_NOT_CONFIGURED"], - error_message="GITLAB_NOT_CONFIGURED", - ) - - host = GITLAB_HOST - - token_url = ( - f"{host}/oauth/token" - ) - userinfo_url = ( - f"{host}/api/v4/user" - ) - provider = "gitlab" scope = "read_user" def __init__(self, request, code=None, state=None, callback=None): - GITLAB_CLIENT_ID, GITLAB_CLIENT_SECRET = get_configuration_value( - [ - { - "key": "GITLAB_CLIENT_ID", - "default": os.environ.get("GITLAB_CLIENT_ID"), - }, - { - "key": "GITLAB_CLIENT_SECRET", - "default": os.environ.get("GITLAB_CLIENT_SECRET"), - }, - ] + GITLAB_CLIENT_ID, GITLAB_CLIENT_SECRET, GITLAB_HOST = ( + get_configuration_value( + [ + { + "key": "GITLAB_CLIENT_ID", + "default": os.environ.get("GITLAB_CLIENT_ID"), + }, + { + "key": "GITLAB_CLIENT_SECRET", + "default": os.environ.get("GITLAB_CLIENT_SECRET"), + }, + { + "key": "GITLAB_HOST", + "default": os.environ.get( + "GITLAB_HOST", "https://gitlab.com" + ), + }, + ] + ) ) - if not (GITLAB_CLIENT_ID and GITLAB_CLIENT_SECRET): + self.host = GITLAB_HOST + self.token_url = f"{self.host}/oauth/token" + self.userinfo_url = f"{self.host}/api/v4/user" + + if not (GITLAB_CLIENT_ID and GITLAB_CLIENT_SECRET and GITLAB_HOST): raise AuthenticationException( error_code=AUTHENTICATION_ERROR_CODES["GITLAB_NOT_CONFIGURED"], error_message="GITLAB_NOT_CONFIGURED", @@ -75,9 +63,7 @@ class GitLabOAuthProvider(OauthAdapter): "scope": self.scope, "state": state, } - auth_url = ( - f"{self.host}/oauth/authorize?{urlencode(url_params)}" - ) + auth_url = f"{self.host}/oauth/authorize?{urlencode(url_params)}" super().__init__( request, self.provider, @@ -98,7 +84,7 @@ class GitLabOAuthProvider(OauthAdapter): "client_secret": self.client_secret, "code": self.code, "redirect_uri": self.redirect_uri, - "grant_type": "authorization_code" + "grant_type": "authorization_code", } token_response = self.get_user_token( data=data, headers={"Accept": "application/json"} @@ -109,7 +95,8 @@ class GitLabOAuthProvider(OauthAdapter): "refresh_token": token_response.get("refresh_token", None), "access_token_expired_at": ( datetime.fromtimestamp( - token_response.get("created_at") + token_response.get("expires_in"), + token_response.get("created_at") + + token_response.get("expires_in"), tz=pytz.utc, ) if token_response.get("expires_in")