Skip to content

Commit

Permalink
Merge pull request #4148 from thematters/develop
Browse files Browse the repository at this point in the history
Release: v5.5.0
  • Loading branch information
gary02 committed Aug 22, 2024
2 parents 4da1ec1 + e1f18ff commit 454222c
Show file tree
Hide file tree
Showing 76 changed files with 2,665 additions and 1,198 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,5 @@ MATTERS_GOOGLE_REDIRECT_URI=

MATTERS_PASSPHRASES_API_URL=
MATTERS_PASSPHRASES_SECRET=

MATTERS_SPAM_DETECTION_API_URL=
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jobs:
NODE_OPTIONS: "--no-experimental-fetch"
CODECOV_TOKEN: de5ab681-0837-4a24-b614-0a29225a7e4c
MATTERS_ENV: test
MATTERS_LOGGING_LEVEL: warn
MATTERS_LOGGING_LEVEL: critical
MATTERS_PG_HOST: localhost
MATTERS_PG_USER: postgres
MATTERS_PG_PASSWORD: postgres
Expand Down
21 changes: 21 additions & 0 deletions db/migrations/20240806102534_alter_article_spam.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const table = 'article'

exports.up = async (knex) => {
await knex.schema.table(table, (t) => {
t.float('spam_score').nullable()
t.boolean('is_spam').nullable()

t.index('spam_score')
t.index('is_spam')
})
}

exports.down = async (knex) => {
await knex.schema.table(table, (t) => {
t.dropIndex('spam_score')
t.dropIndex('is_spam')

t.dropColumn('spam_score')
t.dropColumn('is_spam')
})
}
14 changes: 14 additions & 0 deletions db/migrations/20240806204729_alter_feature_flag_add_value.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const table = 'feature_flag'

exports.up = async (knex) => {
await knex.schema.table(table, (t) => {
t.float('value').nullable()
})
await knex(table).insert({ name: 'spam_detection', flag: 'off', value: 0.5 })
}

exports.down = async (knex) => {
await knex.schema.table(table, (t) => {
t.dropColumn('value')
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const table = 'campaign_article'

exports.up = async (knex) => {
await knex.schema.alterTable(table, (t) => {
t.bigInteger('campaign_stage_id').unsigned().nullable().alter()
})
}

exports.down = async (knex) => {
await knex.schema.alterTable(table, (t) => {
t.bigInteger('campaign_stage_id').unsigned().notNullable().alter()
})
}
13 changes: 13 additions & 0 deletions db/migrations/20240816163354_alter_campaign_description.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const table = 'campaign'

exports.up = async (knex) => {
await knex.schema.alterTable(table, (t) => {
t.text('description').nullable().alter()
})
}

exports.down = async (knex) => {
await knex.schema.alterTable(table, (t) => {
t.text('description').notNullable().alter()
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const table = 'campaign_stage'
const column = 'description'

exports.up = async (knex) => {
await knex.schema.table(table, (t) => {
t.text(column).notNullable().defaultTo('')
})
}

exports.down = async (knex) => {
await knex.schema.table(table, (t) => {
t.dropColumn(column)
})
}
5 changes: 5 additions & 0 deletions db/seeds/31_feature_flag.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,10 @@ exports.seed = async (knex) => {
name: 'verify_appreciate',
flag: 'off',
},
{
name: 'spam_detection',
flag: 'off',
value: 0.5,
},
])
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "matters-server",
"version": "5.4.2",
"version": "5.5.0",
"description": "Matters Server",
"author": "Matters <hi@matters.news>",
"main": "build/index.js",
Expand Down
43 changes: 38 additions & 5 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ type Mutation {
deleteAnnouncements(input: DeleteAnnouncementsInput!): Boolean!
putRestrictedUsers(input: PutRestrictedUsersInput!): [User!]!
putIcymiTopic(input: PutIcymiTopicInput!): IcymiTopic
setSpamStatus(input: SetSpamStatusInput!): Article!

"""Send verification code for email."""
sendVerificationCode(input: SendVerificationCodeInput!): Boolean
Expand Down Expand Up @@ -501,7 +502,7 @@ type Article implements Node & PinnableWork {

type ArticleCampaign {
campaign: Campaign!
stage: CampaignStage!
stage: CampaignStage
}

input ArticleVersionsInput {
Expand Down Expand Up @@ -608,6 +609,17 @@ type ArticleOSS {
inRecommendHottest: Boolean!
inRecommendNewest: Boolean!
inSearch: Boolean!
spamStatus: SpamStatus!
}

type SpamStatus {
"""spam confident score by machine, null for not checked yet. """
score: Float

"""
whether this article is labeled as spam by human, null for not labeled yet.
"""
isSpam: Boolean
}

type ArticleTranslation {
Expand Down Expand Up @@ -877,9 +889,9 @@ input CampaignsInput {
input PutWritingChallengeInput {
id: ID
name: [TranslationInput!]
description: [TranslationInput!]
cover: ID
link: String
announcements: [ID!]
applicationPeriod: DatetimeRangeInput
writingPeriod: DatetimeRangeInput
stages: [CampaignStageInput!]
Expand All @@ -898,6 +910,7 @@ input UpdateCampaignApplicationStateInput {

input CampaignStageInput {
name: [TranslationInput!]!
description: [TranslationInput!]
period: DatetimeRangeInput
}

Expand All @@ -915,7 +928,6 @@ interface Campaign {
id: ID!
shortHash: String!
name: String!
description: String!
state: CampaignState!
}

Expand All @@ -930,9 +942,10 @@ type WritingChallenge implements Node & Campaign {
id: ID!
shortHash: String!
name(input: TranslationArgs): String!
description(input: TranslationArgs): String!
description(input: TranslationArgs): String
cover: String
link: String!
announcements: [Article!]!
applicationPeriod: DatetimeRange
writingPeriod: DatetimeRange
stages: [CampaignStage!]!
Expand Down Expand Up @@ -986,6 +999,7 @@ enum CampaignApplicationState {
type CampaignStage {
id: ID!
name(input: TranslationArgs): String!
description(input: TranslationArgs): String!
period: DatetimeRange
}

Expand Down Expand Up @@ -2039,6 +2053,7 @@ type Official {
type Feature {
name: FeatureName!
enabled: Boolean!
value: Float
}

type Announcement {
Expand Down Expand Up @@ -2067,7 +2082,7 @@ type TranslatedAnnouncement {
type OSS {
users(input: ConnectionArgs!): UserConnection!
comments(input: ConnectionArgs!): CommentConnection!
articles(input: ConnectionArgs!): ArticleConnection!
articles(input: OSSArticlesInput!): ArticleConnection!
tags(input: TagsInput!): TagConnection!
oauthClients(input: ConnectionArgs!): OAuthClientConnection!
skippedListItems(input: SkippedListItemsInput!): SkippedListItemsConnection!
Expand Down Expand Up @@ -2273,6 +2288,7 @@ input ToggleItemInput {
input SetFeatureInput {
name: FeatureName!
flag: FeatureFlag!
value: Float
}

input ToggleSeedingUsersInput {
Expand Down Expand Up @@ -2411,6 +2427,7 @@ enum FeatureName {
tag_adoption
circle_management
circle_interact
spam_detection
}

enum FeatureFlag {
Expand Down Expand Up @@ -2480,6 +2497,21 @@ input PutIcymiTopicInput {
state: IcymiTopicState
}

input SetSpamStatusInput {
id: ID!
isSpam: Boolean!
}

input OSSArticlesInput {
after: String
first: Int
filter: OSSArticlesFilterInput
}

input OSSArticlesFilterInput {
isSpam: Boolean
}

enum CacheControlScope {
PUBLIC
PRIVATE
Expand Down Expand Up @@ -3573,6 +3605,7 @@ input PayToInput {
"""for ERC20/native token payment"""
chain: Chain
txHash: String
id: ID
}

input PayoutInput {
Expand Down
1 change: 1 addition & 0 deletions src/common/enums/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const CACHE_PREFIX = {
USER_LAST_SEEN: 'cache-user-last-seen',
EMAIL_DOMAIL_WHITELIST: 'cache-email-domain-whitelist',
TAG_COVERS: 'cache-tag-covers',
SPAM_THRESHOLD: 'cache-spam-threshold',
}

export const DEFAULT_IPNS_LIFETIME = '7200h' // the maximum, is 300days, almost 1 year
1 change: 1 addition & 0 deletions src/common/enums/feature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const FEATURE_NAME = {
tag_adoption: 'tag_adoption',
circle_management: 'circle_management',
circle_interact: 'circle_interact',
spam_detection: 'spam_detection',
} as const

export const FEATURE_FLAG = {
Expand Down
3 changes: 2 additions & 1 deletion src/common/enums/payment.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { optimism, optimismSepolia, polygon } from 'viem/chains'
import { optimism, optimismSepolia, polygon, polygonMumbai } from 'viem/chains'

import { environment, isProd } from 'common/environment'
import { GQLChain } from 'definitions'
Expand Down Expand Up @@ -51,6 +51,7 @@ export const BLOCKCHAIN: { [key in GQLChain]: GQLChain } = {

export const BLOCKCHAIN_CHAINNAME: { [chainId: string]: GQLChain } = {
[polygon.id]: BLOCKCHAIN.Polygon,
[polygonMumbai.id]: BLOCKCHAIN.Polygon,
[optimism.id]: BLOCKCHAIN.Optimism,
[optimismSepolia.id]: BLOCKCHAIN.Optimism,
} as const
Expand Down
2 changes: 2 additions & 0 deletions src/common/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ export const environment = {

passphrasesApiUrl: process.env.MATTERS_PASSPHRASES_API_URL || '',
passphrasesSecret: process.env.MATTERS_PASSPHRASES_SECRET || '',

spamDetectionApiUrl: process.env.MATTERS_SPAM_DETECTION_API_URL || '',
}

export const contract = {
Expand Down
23 changes: 10 additions & 13 deletions src/common/utils/connections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export interface ConnectionArguments {
before?: ConnectionCursor
after?: ConnectionCursor
first?: number
last?: number
// last?: number
}

export interface Connection<T> {
Expand Down Expand Up @@ -105,23 +105,21 @@ export const loadManyFilterError = <T>(items: Array<T | Error>) =>
*/
export const cursorToKeys = (
cursor: ConnectionCursor | undefined
): { offset: number; idCursor?: number } => {
): { offset: number; idCursor?: string } => {
if (!cursor) {
return { offset: -1 }
}
const keys = Base64.decode(cursor).split(':')
return { offset: parseInt(keys[1], 10), idCursor: parseInt(keys[2], 10) }
return { offset: parseInt(keys[1], 10), idCursor: keys[2] }
}

/**
* Convert query keys to GQL cursor. For example, the query keys
* `arrayconnection:10:39` will be converted to `YXJyYXljb25uZWN0aW9uOjEwOjM5`.
*
*/
export const keysToCursor = (
offset: number,
idCursor: number
): ConnectionCursor => Base64.encodeURI(`${PREFIX}:${offset}:${idCursor}`)
const keysToCursor = (offset: number, idCursor: string): ConnectionCursor =>
Base64.encodeURI(`${PREFIX}:${offset}:${idCursor}`)

/**
* Construct a GQL connection using query keys mechanism. Query keys are
Expand All @@ -130,19 +128,18 @@ export const keysToCursor = (
* and `idCursor` is for SQL querying.
* (for detail explain see https://github.com/thematters/matters-server/pull/922#discussion_r409256544)
*/
export const connectionFromArrayWithKeys = <T extends { id: string }>(
export const connectionFromArrayWithKeys = <
T extends { id: string; __cursor?: string }
>(
data: T[],
args: ConnectionArguments,
args: Pick<ConnectionArguments, 'after'>,
totalCount: number
): Connection<T> => {
const { after } = args
const keys = cursorToKeys(after)

const edges = data.map((value, index) => ({
cursor: keysToCursor(
index + keys.offset + 1,
(value as any).__cursor || value.id
),
cursor: keysToCursor(index + keys.offset + 1, value.__cursor || value.id),
node: value,
}))

Expand Down
5 changes: 5 additions & 0 deletions src/common/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export * from './counter'
export * from './verify'
export * from './nanoid'
export * from './mention'
export * from './knex'

/**
* Make a valid user name based on a given email address. It removes all special characters including _.
Expand Down Expand Up @@ -112,3 +113,7 @@ export const extractRootDomain = (url: string) => {

return parts[2].split('.').slice(-2).join('.')
}

export const isNumeric = (n: string) => {
return /^\d+$/.test(n)
}
Loading

0 comments on commit 454222c

Please sign in to comment.