unread-fixes
This commit is contained in:
parent
6f5b5c364a
commit
e0395b0ab6
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -149,3 +149,4 @@ dev-server.pid
|
|||
backups/
|
||||
poetry.lock
|
||||
.ruff_cache
|
||||
dev-server.pid
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
[0.2.20]
|
||||
- services: ackee removed
|
||||
- services: following manager fixed
|
||||
|
||||
[0.2.19]
|
||||
- fix: adding 'author' role
|
||||
- fix: stripping user_id in auth connector
|
||||
|
|
|
@ -39,7 +39,7 @@ Setup `WEBHOOK_SECRET` env var, webhook payload on `/new-author` is expected whe
|
|||
|
||||
### Viewed
|
||||
|
||||
Set ACKEE_TOKEN var to collect stats
|
||||
Set GOOGLE_ANALYTICS_TOKEN var to collect stats
|
||||
|
||||
### Seacrh
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "discoursio-core"
|
||||
version = "0.2.19"
|
||||
version = "0.2.20"
|
||||
description = "core module for discours.io"
|
||||
authors = ["discoursio devteam"]
|
||||
license = "MIT"
|
||||
|
@ -17,6 +17,9 @@ starlette = "^0.34.0"
|
|||
gql = "^3.4.1"
|
||||
ariadne = "^0.21"
|
||||
aiohttp = "^3.9.1"
|
||||
google-oauth2-tool = "^0.0.3"
|
||||
google-api-python-client = "^2.114.0"
|
||||
pandas = "^2.2.0"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
setuptools = "^69.0.2"
|
||||
|
|
|
@ -1,890 +0,0 @@
|
|||
# Integers that will have a value of 0 or more.
|
||||
scalar UnsignedInt
|
||||
|
||||
# A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar.
|
||||
scalar DateTime
|
||||
|
||||
# Floats that will have a value greater than 0.
|
||||
scalar PositiveFloat
|
||||
|
||||
type Token {
|
||||
# Token identifier. Use this value for authentication.
|
||||
id: ID!
|
||||
|
||||
# Identifies the date and time when the object was created.
|
||||
created: DateTime!
|
||||
|
||||
# Identifies the date and time when the object was updated.
|
||||
updated: DateTime!
|
||||
}
|
||||
|
||||
input CreateTokenInput {
|
||||
# Username used to protect the Ackee instance.
|
||||
username: String!
|
||||
|
||||
# Password used to protect the Ackee instance.
|
||||
password: String!
|
||||
|
||||
# Title of the token.
|
||||
title: String
|
||||
}
|
||||
|
||||
type CreateTokenPayload {
|
||||
# Indicates that the token creation was successful. Might be 'null' otherwise.
|
||||
success: Boolean
|
||||
|
||||
# The newly created token.
|
||||
payload: Token
|
||||
}
|
||||
|
||||
type DeleteTokenPayload {
|
||||
# Indicates that the token deletion was successful. Might be 'null' otherwise.
|
||||
success: Boolean
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
# Create a new token. The token is required in order to access protected data.
|
||||
createToken(input: CreateTokenInput!): CreateTokenPayload!
|
||||
|
||||
# Delete an existing token. The token than can't be used anymore for authentication.
|
||||
deleteToken(id: ID!): DeleteTokenPayload!
|
||||
|
||||
# Create a new permanent token. The token is required in order to access protected data.
|
||||
createPermanentToken(
|
||||
input: CreatePermanentTokenInput!
|
||||
): CreatePermanentTokenPayload!
|
||||
|
||||
# Update an existing permanent token.
|
||||
updatePermanentToken(
|
||||
id: ID!
|
||||
input: UpdatePermanentTokenInput!
|
||||
): UpdatePermanentTokenPayload!
|
||||
|
||||
# Delete an existing permanent token. The token than can't be used anymore for authentication.
|
||||
deletePermanentToken(id: ID!): DeletePermanentTokenPayload!
|
||||
|
||||
# Create a new record to track a page visit.
|
||||
createRecord(domainId: ID!, input: CreateRecordInput!): CreateRecordPayload!
|
||||
|
||||
# Update an existing record to track the duration of a visit.
|
||||
updateRecord(id: ID!): UpdateRecordPayload!
|
||||
|
||||
# Create a new domain.
|
||||
createDomain(input: CreateDomainInput!): CreateDomainPayload!
|
||||
|
||||
# Update an existing domain.
|
||||
updateDomain(id: ID!, input: UpdateDomainInput!): UpdateDomainPayload!
|
||||
|
||||
# Delete an existing domain.
|
||||
deleteDomain(id: ID!): DeleteDomainPayload!
|
||||
|
||||
# Create a new event.
|
||||
createEvent(input: CreateEventInput!): CreateEventPayload!
|
||||
|
||||
# Update an existing event.
|
||||
updateEvent(id: ID!, input: UpdateEventInput!): UpdateEventPayload!
|
||||
|
||||
# Delete an existing event.
|
||||
deleteEvent(id: ID!): DeleteEventPayload!
|
||||
|
||||
# Create a new action to track an event.
|
||||
createAction(eventId: ID!, input: CreateActionInput!): CreateActionPayload!
|
||||
|
||||
# Update an existing action.
|
||||
updateAction(id: ID!, input: UpdateActionInput!): UpdateActionPayload!
|
||||
}
|
||||
|
||||
type PermanentToken {
|
||||
# Permanent token identifier. Use this value for authentication.
|
||||
id: ID!
|
||||
|
||||
# Title of the permanent token.
|
||||
title: String!
|
||||
|
||||
# Identifies the date and time when the object was created.
|
||||
created: DateTime!
|
||||
|
||||
# Identifies the date and time when the object was updated.
|
||||
updated: DateTime!
|
||||
}
|
||||
|
||||
input CreatePermanentTokenInput {
|
||||
# Title of the permanent token.
|
||||
title: String!
|
||||
}
|
||||
|
||||
type CreatePermanentTokenPayload {
|
||||
# Indicates that the permanent token creation was successful. Might be 'null' otherwise.
|
||||
success: Boolean
|
||||
|
||||
# The newly created permanent token.
|
||||
payload: PermanentToken
|
||||
}
|
||||
|
||||
input UpdatePermanentTokenInput {
|
||||
# Title of the permanent token.
|
||||
title: String!
|
||||
}
|
||||
|
||||
type UpdatePermanentTokenPayload {
|
||||
# Indicates that the permanent token update was successful. Might be 'null' otherwise.
|
||||
success: Boolean
|
||||
|
||||
# The updated permanent token.
|
||||
payload: PermanentToken
|
||||
}
|
||||
|
||||
type DeletePermanentTokenPayload {
|
||||
# Indicates that the permanent token deletion was successful. Might be 'null' otherwise.
|
||||
success: Boolean
|
||||
}
|
||||
|
||||
type Query {
|
||||
# Data of a specific permanent token.
|
||||
permanentToken(id: ID!): PermanentToken
|
||||
|
||||
# Data of all existing permanent tokens.
|
||||
permanentTokens: [PermanentToken!]
|
||||
|
||||
# Data of a specific domain.
|
||||
domain(id: ID!): Domain
|
||||
|
||||
# Data of all existing domains.
|
||||
domains: [Domain!]
|
||||
|
||||
# Data of a specific event.
|
||||
event(id: ID!): Event
|
||||
|
||||
# Data of all existing events.
|
||||
events: [Event!]
|
||||
|
||||
# Facts of all domains combined. Usually simple data that can be represented in one value.
|
||||
facts: Facts!
|
||||
|
||||
# Statistics of all domains combined. Usually data that needs to be represented in a list or chart.
|
||||
statistics: DomainStatistics!
|
||||
}
|
||||
|
||||
# Page views will be stored in records. They contain data about the visit and user. Ackee tries its best to keep tracked data anonymized. Several steps are used to avoid that users are identifiable, while still providing helpful analytics.
|
||||
type Record {
|
||||
# Record identifier.
|
||||
id: ID!
|
||||
|
||||
# URL of the page.
|
||||
siteLocation: URL!
|
||||
|
||||
# Where the user came from. Either unknown, a specific page or just the domain. This depends on the browser of the user.
|
||||
siteReferrer: URL
|
||||
|
||||
# Where the user came from. Specified using the source query parameter.
|
||||
source: String
|
||||
|
||||
# Preferred language of the user. ISO 639-1 formatted.
|
||||
siteLanguage: String
|
||||
|
||||
# Width of the screen used by the user to visit the site.
|
||||
screenWidth: UnsignedInt
|
||||
|
||||
# Height of the screen used by the user to visit the site.
|
||||
screenHeight: UnsignedInt
|
||||
|
||||
# Color depth of the screen used by the user to visit the site.
|
||||
screenColorDepth: UnsignedInt
|
||||
|
||||
# Device used by the user to visit the site.
|
||||
deviceName: String
|
||||
|
||||
# Manufacturer of the device used by the user to visit the site.
|
||||
deviceManufacturer: String
|
||||
|
||||
# Operating system used by the user to visit the site.
|
||||
osName: String
|
||||
|
||||
# Operating system version used by the user to visit the site.
|
||||
osVersion: String
|
||||
|
||||
# Browser used by the user to visit the site.
|
||||
browserName: String
|
||||
|
||||
# Version of the browser used by the user to visit the site.
|
||||
browserVersion: String
|
||||
|
||||
# Width of the browser used by the user to visit the site.
|
||||
browserWidth: UnsignedInt
|
||||
|
||||
# Height of the browser used by the user to visit the site.
|
||||
browserHeight: UnsignedInt
|
||||
|
||||
# Identifies the date and time when the object was created.
|
||||
created: DateTime!
|
||||
|
||||
# Identifies the date and time when the object was updated.
|
||||
updated: DateTime!
|
||||
}
|
||||
|
||||
input CreateRecordInput {
|
||||
# URL of the page.
|
||||
siteLocation: URL!
|
||||
|
||||
# Where the user came from. Either unknown, a specific page or just the domain. This depends on the browser of the user.
|
||||
siteReferrer: URL
|
||||
|
||||
# Where the user came from. Specified using the source query parameter.
|
||||
source: String
|
||||
|
||||
# Preferred language of the user. ISO 639-1 formatted.
|
||||
siteLanguage: String
|
||||
|
||||
# Width of the screen used by the user to visit the site.
|
||||
screenWidth: UnsignedInt
|
||||
|
||||
# Height of the screen used by the user to visit the site.
|
||||
screenHeight: UnsignedInt
|
||||
|
||||
# Color depth of the screen used by the user to visit the site.
|
||||
screenColorDepth: UnsignedInt
|
||||
|
||||
# Device used by the user to visit the site.
|
||||
deviceName: String
|
||||
|
||||
# Manufacturer of the device used by the user to visit the site.
|
||||
deviceManufacturer: String
|
||||
|
||||
# Operating system used by the user to visit the site.
|
||||
osName: String
|
||||
|
||||
# Operating system version used by the user to visit the site.
|
||||
osVersion: String
|
||||
|
||||
# Browser used by the user to visit the site.
|
||||
browserName: String
|
||||
|
||||
# Version of the browser used by the user to visit the site.
|
||||
browserVersion: String
|
||||
|
||||
# Width of the browser used by the user to visit the site.
|
||||
browserWidth: UnsignedInt
|
||||
|
||||
# Height of the browser used by the user to visit the site.
|
||||
browserHeight: UnsignedInt
|
||||
}
|
||||
|
||||
type CreateRecordPayload {
|
||||
# Indicates that the record creation was successful. Might be 'null' otherwise.
|
||||
success: Boolean
|
||||
|
||||
# The newly created record.
|
||||
payload: Record
|
||||
}
|
||||
|
||||
type UpdateRecordPayload {
|
||||
# Indicates that the record update was successful. Might be 'null' otherwise.
|
||||
success: Boolean
|
||||
}
|
||||
|
||||
# Domains are required to track views. You can create as many domains as you want, but it's recommended to create on domain per project/site. This allows you to view facts and statistics separately.
|
||||
type Domain {
|
||||
# Domain identifier.
|
||||
id: ID!
|
||||
|
||||
# Title of the domain.
|
||||
title: String!
|
||||
|
||||
# Facts about a domain. Usually simple data that can be represented in one value.
|
||||
facts: Facts!
|
||||
|
||||
# Statistics of a domain. Usually data that needs to be represented in a list or chart.
|
||||
statistics: DomainStatistics!
|
||||
|
||||
# Identifies the date and time when the object was created.
|
||||
created: DateTime!
|
||||
|
||||
# Identifies the date and time when the object was updated.
|
||||
updated: DateTime!
|
||||
}
|
||||
|
||||
input CreateDomainInput {
|
||||
# Title of the domain.
|
||||
title: String!
|
||||
}
|
||||
|
||||
type CreateDomainPayload {
|
||||
# Indicates that the domain creation was successful. Might be 'null' otherwise.
|
||||
success: Boolean
|
||||
|
||||
# The newly created domain.
|
||||
payload: Domain
|
||||
}
|
||||
|
||||
input UpdateDomainInput {
|
||||
# Title of the domain.
|
||||
title: String!
|
||||
}
|
||||
|
||||
type UpdateDomainPayload {
|
||||
# Indicates that the domain update was successful. Might be 'null' otherwise.
|
||||
success: Boolean
|
||||
|
||||
# The updated domain.
|
||||
payload: Domain
|
||||
}
|
||||
|
||||
type DeleteDomainPayload {
|
||||
# Indicates that the domain deletion was successful. Might be 'null' otherwise.
|
||||
success: Boolean
|
||||
}
|
||||
|
||||
enum EventType {
|
||||
# The UI will display the data of this event as a bar chart with totalized values.
|
||||
TOTAL_CHART
|
||||
|
||||
# The UI will display the data of this event as a bar chart with average values.
|
||||
AVERAGE_CHART
|
||||
|
||||
# The UI will display the data of this event as a list of entries with totalized values.
|
||||
TOTAL_LIST
|
||||
|
||||
# The UI will display the data of this event as a list of entries with average values.
|
||||
AVERAGE_LIST
|
||||
}
|
||||
|
||||
# Events are required to track actions. You can create as many events as you want. This allows you to analyse specific actions happening on your sites. Like a button click or a successful sale.
|
||||
type Event {
|
||||
# Event identifier.
|
||||
id: ID!
|
||||
|
||||
# Title of the event.
|
||||
title: String!
|
||||
|
||||
# Type of the event. Allows you to decide how Ackee should display the data of this event in the UI.
|
||||
type: EventType!
|
||||
|
||||
# Statistics of an event. The data is available in different types, depending on whether they are to be shown in a chart or list.
|
||||
statistics: EventStatistics!
|
||||
|
||||
# Identifies the date and time when the object was created.
|
||||
created: DateTime!
|
||||
|
||||
# Identifies the date and time when the object was updated.
|
||||
updated: DateTime!
|
||||
}
|
||||
|
||||
input CreateEventInput {
|
||||
# Title of the event.
|
||||
title: String!
|
||||
|
||||
# Type of the event.
|
||||
type: EventType!
|
||||
}
|
||||
|
||||
type CreateEventPayload {
|
||||
# Indicates that the event creation was successful. Might be 'null' otherwise.
|
||||
success: Boolean
|
||||
|
||||
# The newly created event.
|
||||
payload: Event
|
||||
}
|
||||
|
||||
input UpdateEventInput {
|
||||
# Title of the event.
|
||||
title: String!
|
||||
|
||||
# Type of the event.
|
||||
type: EventType!
|
||||
}
|
||||
|
||||
type UpdateEventPayload {
|
||||
# Indicates that the event update was successful. Might be 'null' otherwise.
|
||||
success: Boolean
|
||||
|
||||
# The updated event.
|
||||
payload: Event
|
||||
}
|
||||
|
||||
type DeleteEventPayload {
|
||||
# Indicates that the event deletion was successful. Might be 'null' otherwise.
|
||||
success: Boolean
|
||||
}
|
||||
|
||||
# Event entries will be stored as actions.
|
||||
type Action {
|
||||
# Action identifier.
|
||||
id: ID!
|
||||
|
||||
# Optional key that will be used to group similar actions in the UI.
|
||||
key: String!
|
||||
|
||||
# Numerical value that is added to all other numerical values of the key, grouped by day, month or year.
|
||||
# Use '1' to count how many times an event occurred or a price (e.g. '1.99') to see the sum of successful checkouts in a shop.
|
||||
value: PositiveFloat!
|
||||
|
||||
# Details allow you to store more data along with the associated action.
|
||||
details: String
|
||||
|
||||
# Identifies the date and time when the object was created.
|
||||
created: DateTime!
|
||||
|
||||
# Identifies the date and time when the object was updated.
|
||||
updated: DateTime!
|
||||
}
|
||||
|
||||
input CreateActionInput {
|
||||
# Key that will be used to group similar actions in the UI.
|
||||
key: String!
|
||||
|
||||
# Numerical value that is added to all other numerical values of the key, grouped by day, month or year.
|
||||
# Use '1' to count how many times an event occurred or a price (e.g. '1.99') to see the sum of successful checkouts in a shop.
|
||||
value: PositiveFloat
|
||||
|
||||
# Details allow you to store more data along with the associated action.
|
||||
details: String
|
||||
}
|
||||
|
||||
type CreateActionPayload {
|
||||
# Indicates that the action creation was successful. Might be 'null' otherwise.
|
||||
success: Boolean
|
||||
|
||||
# The newly created action.
|
||||
payload: Action
|
||||
}
|
||||
|
||||
input UpdateActionInput {
|
||||
# Key that will be used to group similar actions in the UI.
|
||||
key: String!
|
||||
|
||||
# Numerical value that is added to all other numerical values of the key, grouped by day, month or year.
|
||||
# Use '1' to count how many times an event occurred or a price (e.g. '1.99') to see the sum of successful checkouts in a shop.
|
||||
# Reset an existing value using 'null'.
|
||||
value: PositiveFloat
|
||||
|
||||
# Details allow you to store more data along with the associated action.
|
||||
details: String
|
||||
}
|
||||
|
||||
type UpdateActionPayload {
|
||||
# Indicates that the action update was successful. Might be 'null' otherwise.
|
||||
success: Boolean
|
||||
}
|
||||
|
||||
type AverageViews {
|
||||
# Average number of views per day during the last 14 days, excluding the current day.
|
||||
count: UnsignedInt!
|
||||
|
||||
# Percentage change of the average views when comparing the last 7 days with the previous 7 days.
|
||||
# Might be undefined when there's not enough data to compare.
|
||||
change: Float
|
||||
}
|
||||
|
||||
type AverageDuration {
|
||||
# Average visit duration in milliseconds for the last 14 days, excluding the current day.
|
||||
count: UnsignedInt!
|
||||
|
||||
# Percentage change of the average visit duration when comparing the last 7 days with the previous 7 days.
|
||||
# Might be undefined when there's not enough data to compare.
|
||||
change: Float
|
||||
}
|
||||
|
||||
# Facts about a domain. Usually simple data that can be represented in one value.
|
||||
type Facts {
|
||||
# Facts identifier.
|
||||
id: ID!
|
||||
|
||||
# Number of visitors currently on your site.
|
||||
activeVisitors: UnsignedInt!
|
||||
|
||||
# Details about the average number of views.
|
||||
averageViews: AverageViews!
|
||||
|
||||
# Details about the average visit duration.
|
||||
averageDuration: AverageDuration!
|
||||
|
||||
# Number of unique views today.
|
||||
viewsToday: UnsignedInt!
|
||||
|
||||
# Number of unique views this month.
|
||||
viewsMonth: UnsignedInt!
|
||||
|
||||
# Number of unique views this year.
|
||||
viewsYear: UnsignedInt!
|
||||
}
|
||||
|
||||
scalar URL
|
||||
|
||||
enum Interval {
|
||||
# Group by day.
|
||||
DAILY
|
||||
|
||||
# Group by month.
|
||||
MONTHLY
|
||||
|
||||
# Group by year.
|
||||
YEARLY
|
||||
}
|
||||
|
||||
enum Sorting {
|
||||
# Entries with the most occurrences will be shown at the top.
|
||||
TOP
|
||||
|
||||
# Entries sorted by time. The newest entries will be shown at the top.
|
||||
RECENT
|
||||
|
||||
# Entries that appeared for the first time will be shown at the top.
|
||||
NEW
|
||||
}
|
||||
|
||||
enum Range {
|
||||
# Data of the last 24 hours.
|
||||
LAST_24_HOURS
|
||||
|
||||
# Data of the last 7 days.
|
||||
LAST_7_DAYS
|
||||
|
||||
# Data of the last 30 days.
|
||||
LAST_30_DAYS
|
||||
|
||||
# Data of the last 6 months.
|
||||
LAST_6_MONTHS
|
||||
}
|
||||
|
||||
enum ViewType {
|
||||
# Unique site views.
|
||||
UNIQUE
|
||||
|
||||
# Total page views.
|
||||
TOTAL
|
||||
}
|
||||
|
||||
type View {
|
||||
# View identifier.
|
||||
id: ID!
|
||||
|
||||
# Date of visits.
|
||||
# Either YYYY, YYYY-MM or YYYY-MM-DD depending on the current interval.
|
||||
value: String!
|
||||
|
||||
# Amount of occurrences.
|
||||
count: UnsignedInt!
|
||||
}
|
||||
|
||||
type Page {
|
||||
# Page identifier.
|
||||
id: ID!
|
||||
|
||||
# URL of the page.
|
||||
value: URL!
|
||||
|
||||
# Amount of occurrences.
|
||||
count: UnsignedInt
|
||||
|
||||
# Identifies the date and time when the object was created.
|
||||
created: DateTime
|
||||
}
|
||||
|
||||
enum ReferrerType {
|
||||
# Use source parameter instead of referrer when available.
|
||||
WITH_SOURCE
|
||||
|
||||
# Omit source parameters and show referrers only.
|
||||
NO_SOURCE
|
||||
|
||||
# Omit referrers and show source parameters only.
|
||||
ONLY_SOURCE
|
||||
}
|
||||
|
||||
type Referrer {
|
||||
# Referrer identifier.
|
||||
id: ID!
|
||||
|
||||
# Either the URL of the referrer or the source parameter of the page to indicate where the visit comes from.
|
||||
value: String!
|
||||
|
||||
# Amount of occurrences.
|
||||
count: UnsignedInt
|
||||
|
||||
# Identifies the date and time when the object was created.
|
||||
created: DateTime
|
||||
}
|
||||
|
||||
type Duration {
|
||||
# Duration identifier.
|
||||
id: ID!
|
||||
|
||||
# Date of average duration.
|
||||
# Either YYYY, YYYY-MM or YYYY-MM-DD depending on the current interval.
|
||||
value: String!
|
||||
|
||||
# Average duration in milliseconds.
|
||||
count: UnsignedInt!
|
||||
}
|
||||
|
||||
enum SystemType {
|
||||
# Include system version.
|
||||
WITH_VERSION
|
||||
|
||||
# Omit system version.
|
||||
NO_VERSION
|
||||
}
|
||||
|
||||
type System {
|
||||
# System identifier.
|
||||
id: ID!
|
||||
|
||||
# Name of the system. With or without the version.
|
||||
value: String!
|
||||
|
||||
# Amount of occurrences.
|
||||
count: UnsignedInt
|
||||
|
||||
# Identifies the date and time when the object was created.
|
||||
created: DateTime
|
||||
}
|
||||
|
||||
enum DeviceType {
|
||||
# Include model name.
|
||||
WITH_MODEL
|
||||
|
||||
# Omit model name.
|
||||
NO_MODEL
|
||||
}
|
||||
|
||||
type Device {
|
||||
# Device identifier.
|
||||
id: ID!
|
||||
|
||||
# Name of the device. With or without the model.
|
||||
value: String!
|
||||
|
||||
# Amount of occurrences.
|
||||
count: UnsignedInt
|
||||
|
||||
# Identifies the date and time when the object was created.
|
||||
created: DateTime
|
||||
}
|
||||
|
||||
enum BrowserType {
|
||||
# Include browser version.
|
||||
WITH_VERSION
|
||||
|
||||
# Omit browser version.
|
||||
NO_VERSION
|
||||
}
|
||||
|
||||
type Browser {
|
||||
# Browser identifier.
|
||||
id: ID!
|
||||
|
||||
# Name of the browser. With or without the version.
|
||||
value: String!
|
||||
|
||||
# Amount of occurrences.
|
||||
count: UnsignedInt
|
||||
|
||||
# Identifies the date and time when the object was created.
|
||||
created: DateTime
|
||||
}
|
||||
|
||||
enum SizeType {
|
||||
# Browser height in pixels.
|
||||
BROWSER_WIDTH
|
||||
|
||||
# Browser width in pixels.
|
||||
BROWSER_HEIGHT
|
||||
|
||||
# Browser width and height in pixels.
|
||||
BROWSER_RESOLUTION
|
||||
|
||||
# Browser height in pixels.
|
||||
SCREEN_WIDTH
|
||||
|
||||
# Browser width in pixels.
|
||||
SCREEN_HEIGHT
|
||||
|
||||
# Browser width and height in pixels.
|
||||
SCREEN_RESOLUTION
|
||||
}
|
||||
|
||||
type Size {
|
||||
# Size identifier.
|
||||
id: ID!
|
||||
|
||||
# Screen or browser width, height or resolution.
|
||||
value: String!
|
||||
|
||||
# Amount of occurrences.
|
||||
count: UnsignedInt
|
||||
|
||||
# Identifies the date and time when the object was created.
|
||||
created: DateTime
|
||||
}
|
||||
|
||||
type Language {
|
||||
# Language identifier.
|
||||
id: ID!
|
||||
|
||||
# Name of the language or language code when unknown.
|
||||
value: String!
|
||||
|
||||
# Amount of occurrences.
|
||||
count: UnsignedInt
|
||||
|
||||
# Identifies the date and time when the object was created.
|
||||
created: DateTime
|
||||
}
|
||||
|
||||
# Statistics of a domain. Usually data that needs to be represented in a list or chart.
|
||||
type DomainStatistics {
|
||||
# Statistic identifier.
|
||||
id: ID!
|
||||
|
||||
# Amount of views grouped by day, month or year.
|
||||
views(
|
||||
interval: Interval!
|
||||
type: ViewType!
|
||||
|
||||
# Number of entries to return. Starts with the current day, month or year depending on the chosen interval.
|
||||
limit: Int = 14
|
||||
): [View!]
|
||||
|
||||
# Pages viewed by your visitors.
|
||||
pages(
|
||||
sorting: Sorting!
|
||||
range: Range = LAST_7_DAYS
|
||||
|
||||
# Number of entries to return.
|
||||
limit: Int = 30
|
||||
): [Page!]
|
||||
|
||||
# Where your visitors are coming from.
|
||||
referrers(
|
||||
sorting: Sorting!
|
||||
type: ReferrerType!
|
||||
range: Range = LAST_7_DAYS
|
||||
|
||||
# Number of entries to return.
|
||||
limit: Int = 30
|
||||
): [Referrer!]
|
||||
|
||||
# Average visit duration by day, month or year.
|
||||
durations(
|
||||
interval: Interval!
|
||||
|
||||
# Number of entries to return. Starts with the current day, month or year depending on the chosen interval.
|
||||
limit: Int = 14
|
||||
): [Duration!]
|
||||
|
||||
# Systems used by your visitors.
|
||||
systems(
|
||||
sorting: Sorting!
|
||||
type: SystemType!
|
||||
range: Range = LAST_7_DAYS
|
||||
|
||||
# Number of entries to return.
|
||||
limit: Int = 30
|
||||
): [System!]
|
||||
|
||||
# Devices used by your visitors.
|
||||
devices(
|
||||
sorting: Sorting!
|
||||
type: DeviceType!
|
||||
range: Range = LAST_7_DAYS
|
||||
|
||||
# Number of entries to return.
|
||||
limit: Int = 30
|
||||
): [Device!]
|
||||
|
||||
# Browsers used by your visitors.
|
||||
browsers(
|
||||
sorting: Sorting!
|
||||
type: BrowserType!
|
||||
range: Range = LAST_7_DAYS
|
||||
|
||||
# Number of entries to return.
|
||||
limit: Int = 30
|
||||
): [Browser!]
|
||||
|
||||
# Screen or browser sizes used by your visitors.
|
||||
sizes(
|
||||
sorting: Sorting!
|
||||
type: SizeType!
|
||||
range: Range = LAST_7_DAYS
|
||||
|
||||
# Number of entries to return.
|
||||
limit: Int = 30
|
||||
): [Size!]
|
||||
|
||||
# Browser languages used by your visitors.
|
||||
languages(
|
||||
sorting: Sorting!
|
||||
range: Range = LAST_7_DAYS
|
||||
|
||||
# Number of entries to return.
|
||||
limit: Int = 30
|
||||
): [Language!]
|
||||
}
|
||||
|
||||
enum EventChartType {
|
||||
# Total sum of values.
|
||||
TOTAL
|
||||
|
||||
# Average sum of values.
|
||||
AVERAGE
|
||||
}
|
||||
|
||||
enum EventListType {
|
||||
# Total sum of values.
|
||||
TOTAL
|
||||
|
||||
# Average sum of values.
|
||||
AVERAGE
|
||||
}
|
||||
|
||||
type EventChartEntry {
|
||||
# Event entry identifier.
|
||||
id: ID!
|
||||
|
||||
# Date of the event entry.
|
||||
# Either YYYY, YYYY-MM or YYYY-MM-DD depending on the current interval.
|
||||
value: String!
|
||||
|
||||
# Sum of values on that date.
|
||||
count: Float!
|
||||
}
|
||||
|
||||
type EventListEntry {
|
||||
# Event entry identifier.
|
||||
id: ID!
|
||||
|
||||
# Key of the event entry.
|
||||
value: String!
|
||||
|
||||
# Sum of values of the current event key.
|
||||
count: Float
|
||||
|
||||
# Identifies the date and time when the object was created.
|
||||
created: DateTime
|
||||
}
|
||||
|
||||
# Statistics of an event. The data is available in different types, depending on whether they are to be shown in a chart or list.
|
||||
type EventStatistics {
|
||||
# Statistic identifier.
|
||||
id: ID!
|
||||
|
||||
# The chart type should be used when showing events in a chart. It groups events by an interval and shows the total or average sum of values on each entry.
|
||||
chart(
|
||||
interval: Interval!
|
||||
type: EventChartType!
|
||||
|
||||
# Number of entries to return. Starts with the current day, month or year depending on the chosen interval.
|
||||
limit: Int = 14
|
||||
): [EventChartEntry!]
|
||||
|
||||
# The list type should be used when showing events in a list. It groups events by their key and shows the total or average sum of values on each entry.
|
||||
list(
|
||||
sorting: Sorting!
|
||||
type: EventListType!
|
||||
range: Range = LAST_7_DAYS
|
||||
|
||||
# Number of entries to return.
|
||||
limit: Int = 30
|
||||
): [EventListEntry!]
|
||||
}
|
|
@ -1,16 +1,22 @@
|
|||
from services.rediscache import redis
|
||||
import json
|
||||
|
||||
|
||||
async def get_unread_counter(chat_id: str, author_id: int) -> int:
|
||||
unread: int = await redis.execute("LLEN", f"chats/{chat_id}/unread/{author_id}") or 0
|
||||
return unread
|
||||
|
||||
r = await redis.execute("LLEN", f"chats/{chat_id}/unread/{author_id}")
|
||||
if isinstance(r, str):
|
||||
return int(r)
|
||||
elif isinstance(r, int):
|
||||
return r
|
||||
else:
|
||||
return 0
|
||||
|
||||
async def get_total_unread_counter(author_id: int) -> int:
|
||||
chats_set = await redis.execute("SMEMBERS", f"chats_by_author/{author_id}")
|
||||
unread = 0
|
||||
if chats_set:
|
||||
for chat_id in list(chats_set):
|
||||
n = await get_unread_counter(chat_id, author_id)
|
||||
unread += n
|
||||
return unread
|
||||
s = 0
|
||||
if isinstance(chats_set, str):
|
||||
chats_set = json.loads(chats_set)
|
||||
if isinstance(chats_set, list):
|
||||
for chat_id in chats_set:
|
||||
s += await get_unread_counter(chat_id, author_id)
|
||||
return s
|
||||
|
|
|
@ -1,77 +1,30 @@
|
|||
import asyncio
|
||||
import threading
|
||||
import os
|
||||
from typing import Dict
|
||||
from logging import Logger
|
||||
import logging
|
||||
import time
|
||||
import json
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from os import environ
|
||||
import logging
|
||||
from gql import Client, gql
|
||||
from gql.transport.aiohttp import AIOHTTPTransport
|
||||
from graphql import DocumentNode
|
||||
from orm.author import Author
|
||||
|
||||
from orm.shout import Shout, ShoutAuthor, ShoutTopic
|
||||
from orm.topic import Topic
|
||||
from services.db import local_session
|
||||
# ga
|
||||
from apiclient.discovery import build
|
||||
from google.oauth2.service_account import Credentials
|
||||
import pandas as pd
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logger = logging.getLogger("\t[services.viewed]\t")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
GOOGLE_KEYFILE_PATH = os.environ.get("GOOGLE_KEYFILE_PATH", '/dump/google-service.json')
|
||||
|
||||
load_facts = gql(
|
||||
""" query getDomains {
|
||||
domains {
|
||||
id
|
||||
title
|
||||
facts {
|
||||
activeVisitors
|
||||
viewsToday
|
||||
viewsMonth
|
||||
viewsYear
|
||||
}
|
||||
} } """
|
||||
)
|
||||
|
||||
load_pages = gql(
|
||||
""" query getDomains {
|
||||
domains {
|
||||
title
|
||||
statistics {
|
||||
pages(sorting: TOP) {
|
||||
# id
|
||||
count
|
||||
# created
|
||||
value
|
||||
}
|
||||
}
|
||||
} } """
|
||||
)
|
||||
|
||||
create_record_mutation_string = """
|
||||
createRecord(domainId: $domainId, input: $input) {
|
||||
payload {
|
||||
id
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
create_record_mutation = gql(f"mutation {{{create_record_mutation_string}}}")
|
||||
|
||||
schema_str = open("schemas/ackee.graphql").read()
|
||||
token = environ.get("ACKEE_TOKEN", "")
|
||||
domain_id = environ.get("ACKEE_DOMAIN_ID", "")
|
||||
ackee_site = environ.get("ACKEE_SITE", "https://testing.discours.io/")
|
||||
|
||||
|
||||
def create_client(headers=None, schema=None):
|
||||
transport = AIOHTTPTransport(
|
||||
url="https://ackee.discours.io/api",
|
||||
headers=headers,
|
||||
# Build Analytics Reporting API V4 service object.
|
||||
def get_service():
|
||||
SCOPES = ['https://www.googleapis.com/auth/analytics.readonly']
|
||||
credentials = Credentials.from_service_account_file(
|
||||
GOOGLE_KEYFILE_PATH, scopes=SCOPES
|
||||
)
|
||||
return Client(schema=schema, transport=transport)
|
||||
service = build(serviceName='analyticsreporting', version='v4', credentials=credentials)
|
||||
return service
|
||||
|
||||
|
||||
class ViewedStorage:
|
||||
|
@ -81,21 +34,20 @@ class ViewedStorage:
|
|||
shouts_by_author = {}
|
||||
views = None
|
||||
pages = None
|
||||
domains = None
|
||||
facts = None
|
||||
period = 60 * 60 # every hour
|
||||
client: Client | None = None
|
||||
analytics_client = None
|
||||
auth_result = None
|
||||
disabled = False
|
||||
|
||||
@staticmethod
|
||||
async def init():
|
||||
"""graphql client connection using permanent token"""
|
||||
"""Google Analytics client connection using authentication"""
|
||||
self = ViewedStorage
|
||||
async with self.lock:
|
||||
if token:
|
||||
self.client = create_client({"Authorization": f"Bearer {token}"}, schema=schema_str)
|
||||
logger.info(" * authorized permanently by ackee.discours.io: %s" % token)
|
||||
if os.path.exists(GOOGLE_KEYFILE_PATH):
|
||||
self.analytics_client = get_service()
|
||||
logger.info(" * authorized permanently by Google Analytics")
|
||||
|
||||
# Load pre-counted views from the JSON file
|
||||
self.load_precounted_views()
|
||||
|
@ -103,7 +55,7 @@ class ViewedStorage:
|
|||
views_stat_task = asyncio.create_task(self.worker())
|
||||
logger.info(views_stat_task)
|
||||
else:
|
||||
logger.info(" * please set ACKEE_TOKEN")
|
||||
logger.info(" * please add Google Analytics keyfile")
|
||||
self.disabled = True
|
||||
|
||||
@staticmethod
|
||||
|
|
Loading…
Reference in New Issue
Block a user