Browse Source

fix: feed new endpoint apis

pull/9323/head
DarkPhoenix2704 2 months ago
parent
commit
4cef7b2373
  1. 4
      packages/nc-gui/components/feed/Changelog/Item.vue
  2. 30
      packages/nc-gui/components/feed/Recents/Card.vue
  3. 2
      packages/nc-gui/components/feed/Youtube/Player.vue
  4. 12
      packages/nc-gui/components/feed/Youtube/index.vue
  5. 13
      packages/nocodb/src/controllers/utils.controller.ts
  6. 103
      packages/nocodb/src/services/utils.service.ts
  7. 1
      packages/nocodb/src/utils/globals.ts

4
packages/nc-gui/components/feed/Changelog/Item.vue

@ -126,6 +126,10 @@ const renderedText = computedAsync(async () => {
img {
@apply !rounded-lg;
}
h1 {
@apply !text-3xl !font-bold;
}
}
.aside {

30
packages/nc-gui/components/feed/Recents/Card.vue

@ -53,8 +53,13 @@ const renderedText = computedAsync(async () => {
</div>
</div>
<template v-if="source === 'Github'">
<LazyCellAttachmentPreviewImage v-if="Images?.length" :srcs="getPossibleAttachmentSrc(Images[0], 'card_cover')" />
<div class="prose px-5 mt-5" v-html="renderedText"></div>
<LazyCellAttachmentPreviewImage
v-if="Images?.length"
class="cursor-pointer"
:srcs="getPossibleAttachmentSrc(Images[0], 'card_cover')"
@click="openLink(Url)"
/>
<div class="prose px-5 pb-5 mt-5" v-html="renderedText"></div>
</template>
<template v-else-if="source === 'Youtube'">
<YoutubeVue3 :videoid="extractYoutubeVideoId(Url)" :controls="1" :height="410" :width="656" :autoplay="0" />
@ -71,14 +76,21 @@ const renderedText = computedAsync(async () => {
</div>
</template>
<style scoped lang="scss">
.prose {
a {
@apply !text-gray-900;
}
}
<style lang="scss">
.recent-card {
box-shadow: 0px 4px 8px -2px rgba(0, 0, 0, 0.08), 0px 2px 4px -2px rgba(0, 0, 0, 0.04);
.prose {
a {
@apply !text-gray-900;
}
h1 {
@apply !text-2xl !font-semibold truncate;
}
p {
@apply !text-md !leading-6;
}
}
}
</style>

2
packages/nc-gui/components/feed/Youtube/Player.vue

@ -14,7 +14,7 @@ const {
</script>
<template>
<div class="mt-6 border-1 !bg-white recent-card rounded-2xl border-gray-200">
<div class="mt-6 border-1 !bg-white recent-card !rounded-2xl border-gray-200">
<YoutubeVue3
:videoid="extractYoutubeVideoId(Url)"
class="!rounded-t-xl"

12
packages/nc-gui/components/feed/Youtube/index.vue

@ -35,17 +35,21 @@ const gotoChannel = () => {
<div v-else-if="isLoading && !youtubeFeed.length" class="flex items-center justify-center h-full w-full">
<GeneralLoader size="xlarge" />
</div>
<div v-else class="max-w-[764px] mx-auto">
<div class="flex gap-3 items-center justify-between">
<div v-else class="youtube-feed mx-auto">
<div class="flex gap-3 items-center mt-4 justify-between">
<span class="text-gray-900 font-semibold"> Recent Videos </span>
<NcButton type="secondary" size="small" @click="gotoChannel"> Go to Youtube </NcButton>
</div>
<div class="flex gap-2 flex-col">
<FeedYoutubePlayer v-for="feed in youtubeFeed" :key="feed.id" :item="feed" />
<FeedYoutubePlayer v-for="feed in youtubeFeed" :key="feed.Id" :item="feed" />
</div>
</div>
</div>
</template>
<style scoped lang="scss"></style>
<style scoped lang="scss">
.youtube-feed {
@apply !max-w-[47.75rem];
}
</style>

13
packages/nocodb/src/controllers/utils.controller.ts

@ -7,6 +7,7 @@ import {
HttpCode,
Post,
Req,
Request,
UseGuards,
} from '@nestjs/common';
import { ProjectRoles, validateAndExtractSSLProp } from 'nocodb-sdk';
@ -166,4 +167,16 @@ export class UtilsController {
// todo: refactor
return (await this.utilsService.aggregatedMetaInfo()) as any;
}
@UseGuards(PublicApiLimiterGuard)
@Get('/api/v1/feed')
async feed(@Request() req: NcRequest) {
return await this.utilsService.feed(req);
}
@UseGuards(PublicApiLimiterGuard)
@Get('/api/v1/new-feed')
async newFeed(@Request() req: NcRequest) {
return await this.utilsService.getLatestFeed(req);
}
}

103
packages/nocodb/src/services/utils.service.ts

@ -5,7 +5,7 @@ import { compareVersions, validate } from 'compare-versions';
import { ViewTypes } from 'nocodb-sdk';
import { ConfigService } from '@nestjs/config';
import { useAgent } from 'request-filtering-agent';
import type { AppConfig } from '~/interface/config';
import type { AppConfig, NcRequest } from '~/interface/config';
import { NC_APP_SETTINGS, NC_ATTACHMENT_FIELD_SIZE } from '~/constants';
import SqlMgrv2 from '~/db/sql-mgr/v2/SqlMgrv2';
import { NcError } from '~/helpers/catchError';
@ -13,7 +13,7 @@ import { Base, Store, User } from '~/models';
import Noco from '~/Noco';
import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2';
import getInstance from '~/utils/getInstance';
import { MetaTable, RootScopes } from '~/utils/globals';
import { CacheScope, MetaTable, RootScopes } from '~/utils/globals';
import { jdbcToXcConfig } from '~/utils/nc-config/helpers';
import { packageVersion } from '~/utils/packageVersion';
import {
@ -21,6 +21,8 @@ import {
defaultLimitConfig,
} from '~/helpers/extractLimitAndOffset';
import { DriverClient } from '~/utils/nc-config';
import NocoCache from '~/cache/NocoCache';
import { getCircularReplacer } from '~/utils';
const versionCache = {
releaseVersion: null,
@ -385,7 +387,6 @@ export class UtilsService {
if (result.status === 'fulfilled') {
return result.value;
}
console.log(result.reason);
return null;
});
};
@ -460,6 +461,7 @@ export class UtilsService {
disableEmailAuth: this.configService.get('auth.disableEmailAuth', {
infer: true,
}),
feedEnabled: process.env.NC_DISABLE_PRODUCT_FEED !== 'true',
mainSubDomain: this.configService.get('mainSubDomain', { infer: true }),
dashboardPath: this.configService.get('dashboardPath', { infer: true }),
inviteOnlySignup: settings.invite_only_signup,
@ -471,4 +473,99 @@ export class UtilsService {
return result;
}
async feed(req: NcRequest) {
const {
type = 'all',
page = '1',
per_page = '10',
} = req.query as {
type: 'github' | 'youtube' | 'all' | 'twitter' | 'cloud';
page: string;
per_page: string;
};
const cacheKey = `${CacheScope.PRODUCT_FEED}:${type}:${page}:${per_page}`;
const cachedData = await NocoCache.get(cacheKey, 'json');
if (cachedData) {
try {
return JSON.parse(cachedData);
} catch (e) {
console.log(e);
}
}
let response;
try {
response = await axios.get('https://nocodb.com/api/v1/social/feed', {
params: {
per_page,
page,
type,
},
});
} catch (e) {
console.log(e);
return [];
}
// The feed includes the attachments, which has the presigned URL
// So the cache should match the presigned URL cache
await NocoCache.setExpiring(
cacheKey,
JSON.stringify(response.data, getCircularReplacer),
isNaN(parseInt(process.env.NC_ATTACHMENT_EXPIRE_SECONDS))
? 2 * 60 * 60
: parseInt(process.env.NC_ATTACHMENT_EXPIRE_SECONDS),
);
return response.data;
}
async getLatestFeed(req: NcRequest) {
const { last_published_at } = req.query as {
last_published_at: string;
};
if (!last_published_at) {
return 0;
}
const utils = {
found: false,
page: 1,
missedItems: 0,
};
while (!utils.found) {
const feed = await this.feed({
query: {
type: 'all',
page: utils.page.toString(),
per_page: '100',
},
} as unknown as NcRequest);
if (!feed || !feed?.length) {
break;
}
for (const item of feed) {
if (item['Published Time'] === last_published_at) {
utils.found = true;
break;
}
utils.missedItems++;
}
if (!utils.found) {
utils.page++;
}
}
return utils.missedItems;
}
}

1
packages/nocodb/src/utils/globals.ts

@ -187,6 +187,7 @@ export enum CacheScope {
INTEGRATION = 'integration',
COL_BUTTON = 'colButton',
CMD_PALETTE = 'cmdPalette',
PRODUCT_FEED = 'productFeed',
}
export enum CacheGetType {

Loading…
Cancel
Save