Initial commit

This commit is contained in:
Sonny Bakker 2025-03-23 21:20:21 +01:00
parent b465d0bb8d
commit 91a0459186
8 changed files with 8 additions and 128 deletions

View file

@ -29,11 +29,6 @@ x-django-env: &django-env
EMAIL_USE_SSL: EMAIL_USE_SSL:
EMAIL_DEFAULT_FROM: EMAIL_DEFAULT_FROM:
# Reddit
REDDIT_CLIENT_ID:
REDDIT_CLIENT_SECRET:
REDDIT_CALLBACK_URL:
# Sentry # Sentry
SENTRY_DSN: SENTRY_DSN:

View file

@ -209,16 +209,6 @@ STATICFILES_FINDERS = [
# Email # Email
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
# Reddit integration
REDDIT_CLIENT_ID = "CLIENT_ID"
REDDIT_CLIENT_SECRET = "CLIENT_SECRET"
REDDIT_REDIRECT_URL = (
"http://127.0.0.1:8000/accounts/settings/integrations/reddit/callback/"
)
# Twitter integration
TWITTER_URL = "https://twitter.com"
# Third party settings # Third party settings
AXES_HANDLER = "axes.handlers.cache.AxesCacheHandler" AXES_HANDLER = "axes.handlers.cache.AxesCacheHandler"
AXES_CACHE = "axes" AXES_CACHE = "axes"

View file

@ -48,11 +48,6 @@ EMAIL_USE_SSL = bool(os.environ.get("EMAIL_USE_SSL"))
VERSION = get_current_version(debug=False) VERSION = get_current_version(debug=False)
ENVIRONMENT = "production" ENVIRONMENT = "production"
# Reddit integration
REDDIT_CLIENT_ID = os.environ.get("REDDIT_CLIENT_ID", "")
REDDIT_CLIENT_SECRET = os.environ.get("REDDIT_CLIENT_SECRET", "")
REDDIT_REDIRECT_URL = os.environ.get("REDDIT_CALLBACK_URL", "")
# Third party settings # Third party settings
AXES_HANDLER = "axes.handlers.database.AxesDatabaseHandler" AXES_HANDLER = "axes.handlers.database.AxesDatabaseHandler"

View file

@ -3,7 +3,7 @@ import { connect } from 'react-redux';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { unSelectPost, markPostRead, toggleSaved } from '../actions/posts.js'; import { unSelectPost, markPostRead, toggleSaved } from '../actions/posts.js';
import { SAVED_TYPE, SUBREDDIT } from '../constants.js'; import { SAVED_TYPE } from '../constants.js';
import { formatDatetime } from '../../../utils.js'; import { formatDatetime } from '../../../utils.js';
class PostModal extends React.Component { class PostModal extends React.Component {
@ -25,13 +25,16 @@ class PostModal extends React.Component {
if (this.readTimer) { if (this.readTimer) {
clearTimeout(this.readTimer); clearTimeout(this.readTimer);
} }
}
modalListener = (e) => {
const targetClassName = e.target.className;
this.readTimer = null; this.readTimer = null;
window.removeEventListener('click', this.modalListener); window.removeEventListener('click', this.modalListener);
} }
modalListener = (e) => { modalListener(e) {
const targetClassName = e.target.className; const targetClassName = e.target.className;
if (this.props.post && targetClassName == 'modal post-modal') { if (this.props.post && targetClassName == 'modal post-modal') {
@ -53,9 +56,6 @@ class PostModal extends React.Component {
let ruleUrl = ''; let ruleUrl = '';
switch (this.props.rule.type) { switch (this.props.rule.type) {
case SUBREDDIT:
ruleUrl = `${this.props.subredditUrl}/${this.props.rule.id}/`;
break;
default: default:
ruleUrl = `${this.props.feedUrl}/${this.props.rule.id}/`; ruleUrl = `${this.props.feedUrl}/${this.props.rule.id}/`;
break; break;
@ -69,7 +69,7 @@ class PostModal extends React.Component {
<div className="post__actions"> <div className="post__actions">
<button <button
className={`button read-button ${readButtonDisabled && className={`button read-button ${readButtonDisabled &&
'button--disabled'}`} 'button--disabled'}`}
onClick={() => onClick={() =>
!readButtonDisabled && this.props.markPostRead(post, token) !readButtonDisabled && this.props.markPostRead(post, token)
} }

View file

@ -2,7 +2,7 @@ import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { CATEGORY_TYPE, SAVED_TYPE, SUBREDDIT } from '../../constants.js'; import { CATEGORY_TYPE, SAVED_TYPE } from '../../constants.js';
import { selectPost, toggleSaved } from '../../actions/posts.js'; import { selectPost, toggleSaved } from '../../actions/posts.js';
import { formatDatetime } from '../../../../utils.js'; import { formatDatetime } from '../../../../utils.js';
@ -18,12 +18,7 @@ class PostItem extends React.Component {
: 'posts__header'; : 'posts__header';
const savedIconClass = post.saved ? 'saved-icon saved-icon--saved' : 'saved-icon'; const savedIconClass = post.saved ? 'saved-icon saved-icon--saved' : 'saved-icon';
let ruleUrl = ''; const ruleUrl = `${this.props.feedUrl}/${rule.id}/`;
if (rule.type === SUBREDDIT) {
ruleUrl = `${this.props.subredditUrl}/${rule.id}/`;
} else {
ruleUrl = `${this.props.feedUrl}/${rule.id}/`;
}
return ( return (
<li className="posts__item" ref={this.props.forwardedRef}> <li className="posts__item" ref={this.props.forwardedRef}>

View file

@ -2,5 +2,4 @@ export const RULE_TYPE = 'RULE';
export const CATEGORY_TYPE = 'CATEGORY'; export const CATEGORY_TYPE = 'CATEGORY';
export const SAVED_TYPE = 'SAVED'; export const SAVED_TYPE = 'SAVED';
export const SUBREDDIT = 'subreddit';
export const FEED = 'feed'; export const FEED = 'feed';

View file

@ -1,4 +1,3 @@
from django.conf import settings
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
@ -84,13 +83,6 @@ class CollectionRule(TimeStampedModel):
@property @property
def source_url(self): def source_url(self):
if self.type == RuleTypeChoices.subreddit:
from newsreader.news.collection.reddit import REDDIT_API_URL, REDDIT_URL
return self.url.replace(REDDIT_API_URL, REDDIT_URL)
elif self.type == RuleTypeChoices.twitter_timeline:
return f"{settings.TWITTER_URL}/{self.screen_name}"
return self.url return self.url
@property @property

View file

@ -1,19 +1,13 @@
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.core.mail import send_mail
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
import requests
from celery.exceptions import Reject from celery.exceptions import Reject
from celery.utils.log import get_task_logger from celery.utils.log import get_task_logger
from newsreader.accounts.models import User from newsreader.accounts.models import User
from newsreader.celery import app from newsreader.celery import app
from newsreader.news.collection.choices import RuleTypeChoices from newsreader.news.collection.choices import RuleTypeChoices
from newsreader.news.collection.exceptions.stream import StreamException
from newsreader.news.collection.feed import FeedCollector from newsreader.news.collection.feed import FeedCollector
from newsreader.news.collection.utils import post
from newsreader.utils.celery import MemCacheLock from newsreader.utils.celery import MemCacheLock
@ -49,84 +43,6 @@ class FeedTask(app.Task):
raise Reject(reason="Task already running", requeue=False) raise Reject(reason="Task already running", requeue=False)
class RedditTask(app.Task):
name = "RedditTask"
ignore_result = True
def run(self):
from newsreader.news.collection.reddit import RedditCollector, RedditScheduler
with MemCacheLock("reddit-task", self.app.oid) as acquired:
if acquired:
logger.info("Running reddit task")
scheduler = RedditScheduler()
subreddits = scheduler.get_scheduled_rules()
collector = RedditCollector()
collector.collect(rules=subreddits)
else:
logger.warning("Cancelling task due to existing lock")
raise Reject(reason="Task already running", requeue=False)
class RedditTokenTask(app.Task):
name = "RedditTokenTask"
ignore_result = True
def run(self, user_pk):
from newsreader.news.collection.reddit import REDDIT_URL
try:
user = User.objects.get(pk=user_pk)
except ObjectDoesNotExist:
message = f"User {user_pk} does not exist"
logger.exception(message)
raise Reject(reason=message, requeue=False)
if not user.reddit_refresh_token:
raise Reject(reason=f"User {user_pk} has no refresh token", requeue=False)
client_auth = requests.auth.HTTPBasicAuth(
settings.REDDIT_CLIENT_ID, settings.REDDIT_CLIENT_SECRET
)
try:
response = post(
f"{REDDIT_URL}/api/v1/access_token",
data={
"grant_type": "refresh_token",
"refresh_token": user.reddit_refresh_token,
},
auth=client_auth,
)
except StreamException:
logger.exception(
f"Failed refreshing reddit access token for user {user_pk}"
)
user.reddit_refresh_token = None
user.save()
message = _(
"Your Reddit account credentials have expired. Re-authenticate in"
" the settings page to keep retrieving Reddit specific information"
" from your account."
)
send_mail(
"Reddit account needs re-authentication", message, None, [user.email]
)
return
response_data = response.json()
user.reddit_access_token = response_data["access_token"]
user.save()
class FaviconTask(app.Task): class FaviconTask(app.Task):
name = "FaviconTask" name = "FaviconTask"
ignore_result = True ignore_result = True
@ -167,5 +83,3 @@ class FaviconTask(app.Task):
FeedTask = app.register_task(FeedTask()) FeedTask = app.register_task(FeedTask())
FaviconTask = app.register_task(FaviconTask()) FaviconTask = app.register_task(FaviconTask())
RedditTask = app.register_task(RedditTask())
RedditTokenTask = app.register_task(RedditTokenTask())