mirror of
https://github.com/filecoin-project/slate.git
synced 2024-09-11 22:07:08 +03:00
stylistic changes and fixes, as well as resolving bugs
This commit is contained in:
parent
ef725d8040
commit
d99e5d7d28
@ -210,11 +210,13 @@ export const error = {
|
||||
SERVER_FILECOIN_NETWORK_ERROR: "We're having trouble fetching your storage information right now",
|
||||
|
||||
//Sign in
|
||||
SIGN_UP_RATE_LIMITED: "Too many signup attempts. Please try again in 10 minutes",
|
||||
SIGN_IN_RATE_LIMITED: "Too many login attempts. Please try again in 10 minutes",
|
||||
SERVER_SIGN_IN_NOT_ALLOWED: "You can only sign in to an account while on slate.host",
|
||||
SERVER_SIGN_IN_NO_USERNAME: "Please provide a username to sign in",
|
||||
SERVER_SIGN_IN_NO_PASSWORD: "Please provide a password to sign in",
|
||||
SERVER_SIGN_IN_USER_NOT_FOUND: "We were unable to locate that account with those credentials",
|
||||
SERVER_SIGN_IN_WRONG_CREDENTIALS: "You have entered an invalid username or password",
|
||||
SERVER_SIGN_IN_WRONG_CREDENTIALS: "The username and password do not match",
|
||||
|
||||
//Subscribe
|
||||
SERVER_SUBSCRIBE_MUST_PROVIDE_SLATE_OR_USER: "No collection or user to follow specified",
|
||||
|
@ -31,7 +31,8 @@ export const authenticate = async (state) => {
|
||||
}
|
||||
|
||||
let response = await Actions.signIn(state);
|
||||
if (!response || response.error) {
|
||||
|
||||
if (Events.hasError(response)) {
|
||||
return response;
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ export class Alert extends React.Component {
|
||||
_handleDismissPrivacyAlert = (e) => {
|
||||
Actions.updateStatus({ onboarding: ["hidePrivacyAlert"] });
|
||||
this.props.onAction({
|
||||
type: "UDPATE_VIEWER",
|
||||
type: "UPDATE_VIEWER",
|
||||
viewer: {
|
||||
onboarding: { ...this.props.viewer.onboarding, hidePrivacyAlert: true },
|
||||
},
|
||||
|
@ -182,7 +182,7 @@ export default function Signin({
|
||||
);
|
||||
}
|
||||
return (
|
||||
<SignUpPopover title={`Enter Password for ${emailOrUsername}`}>
|
||||
<SignUpPopover title={`Enter Password for ${emailOrUsername.toLowerCase()}`}>
|
||||
<form {...getFormProps()} style={{ marginTop: message ? 24 : 41 }}>
|
||||
{message && (
|
||||
<div css={STYLES_MESSAGE}>
|
||||
|
@ -552,7 +552,7 @@ class CarouselSidebar extends React.Component {
|
||||
...STYLES_INPUT,
|
||||
}}
|
||||
textStyle={{ color: Constants.system.white }}
|
||||
maxlength="255"
|
||||
maxLength="255"
|
||||
/>
|
||||
|
||||
<Textarea
|
||||
@ -561,7 +561,7 @@ class CarouselSidebar extends React.Component {
|
||||
value={this.state.body}
|
||||
onChange={this._handleChange}
|
||||
style={STYLES_INPUT}
|
||||
maxlength="2000"
|
||||
maxLength="2000"
|
||||
/>
|
||||
<Input
|
||||
full
|
||||
@ -572,7 +572,7 @@ class CarouselSidebar extends React.Component {
|
||||
id={`sidebar-label-source`}
|
||||
style={STYLES_INPUT}
|
||||
textStyle={{ color: Constants.system.white }}
|
||||
maxlength="255"
|
||||
maxLength="255"
|
||||
/>
|
||||
<Input
|
||||
full
|
||||
@ -583,7 +583,7 @@ class CarouselSidebar extends React.Component {
|
||||
id={`sidebar-label-author`}
|
||||
style={{ ...STYLES_INPUT, marginBottom: 12 }}
|
||||
textStyle={{ color: Constants.system.white }}
|
||||
maxlength="255"
|
||||
maxLength="255"
|
||||
/>
|
||||
{/* <div css={STYLES_OPTIONS_SECTION}>
|
||||
<Tag
|
||||
|
@ -12,10 +12,11 @@ const STYLES_BUTTON = (theme) => css`
|
||||
background-color: ${theme.semantic.bgBlurWhite};
|
||||
padding: 8px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 0 1px ${theme.system.grayLight5}, ${theme.shadow.lightLarge};
|
||||
box-shadow: 0 0 0 1px ${theme.semantic.borderGrayLight};
|
||||
|
||||
transition: box-shadow 0.3s;
|
||||
:hover {
|
||||
box-shadow: 0 0 0 1px ${theme.system.pink}, ${theme.shadow.lightLarge};
|
||||
box-shadow: 0 0 0 1px ${theme.system.blue}, ${theme.shadow.lightLarge};
|
||||
}
|
||||
|
||||
path {
|
||||
@ -23,12 +24,27 @@ const STYLES_BUTTON = (theme) => css`
|
||||
}
|
||||
|
||||
:hover path {
|
||||
stroke: ${theme.system.pink};
|
||||
stroke: ${theme.system.blue};
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_DISABLED = css`
|
||||
const STYLES_DISABLED = (theme) => css`
|
||||
display: flex;
|
||||
background-color: ${theme.semantic.bgBlurWhite};
|
||||
padding: 8px;
|
||||
border-radius: 8px;
|
||||
${"" /* box-shadow: 0 0 0 1px ${theme.system.gray}, ${theme.shadow.lightLarge}; */}
|
||||
box-shadow: 0 0 0 1px ${theme.semantic.borderGrayLight};
|
||||
transition: box-shadow 0.3s;
|
||||
cursor: not-allowed;
|
||||
|
||||
path {
|
||||
transition: stroke 0.3s;
|
||||
}
|
||||
|
||||
path {
|
||||
stroke: ${theme.system.gray};
|
||||
}
|
||||
`;
|
||||
|
||||
const animate = async (controls) => {
|
||||
@ -48,12 +64,12 @@ export default function FollowButton({ onFollow, isFollowed, disabled, followCou
|
||||
|
||||
return (
|
||||
<motion.button
|
||||
css={[Styles.BUTTON_RESET, STYLES_BUTTON, disabled && STYLES_DISABLED]}
|
||||
css={[Styles.BUTTON_RESET, disabled ? STYLES_DISABLED : STYLES_BUTTON]}
|
||||
initial={{
|
||||
backgroundColor: isFollowed ? Constants.system.redLight6 : Constants.semantic.bgBlurWhite,
|
||||
backgroundColor: isFollowed ? Constants.system.blueLight6 : Constants.semantic.bgBlurWhite,
|
||||
}}
|
||||
animate={{
|
||||
backgroundColor: isFollowed ? Constants.system.redLight6 : Constants.semantic.bgBlurWhite,
|
||||
backgroundColor: isFollowed ? Constants.system.blueLight6 : Constants.semantic.bgBlurWhite,
|
||||
}}
|
||||
onClick={(e) => {
|
||||
if (disabled) {
|
||||
@ -75,24 +91,24 @@ export default function FollowButton({ onFollow, isFollowed, disabled, followCou
|
||||
>
|
||||
<motion.path
|
||||
d="M3.33334 9.66669C5.32247 9.66669 7.23012 10.4569 8.63664 11.8634C10.0432 13.2699 10.8333 15.1776 10.8333 17.1667"
|
||||
initial={{ stroke: isFollowed ? Constants.system.pink : Constants.system.black }}
|
||||
animate={{ stroke: isFollowed ? Constants.system.pink : Constants.system.black }}
|
||||
initial={{ stroke: isFollowed ? Constants.system.blue : Constants.system.black }}
|
||||
animate={{ stroke: isFollowed ? Constants.system.blue : Constants.system.black }}
|
||||
strokeWidth={1.25}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<motion.path
|
||||
d="M3.33334 3.83331C6.86956 3.83331 10.2609 5.23807 12.7614 7.73856C15.2619 10.239 16.6667 13.6304 16.6667 17.1666"
|
||||
initial={{ stroke: isFollowed ? Constants.system.pink : Constants.system.black }}
|
||||
animate={{ stroke: isFollowed ? Constants.system.pink : Constants.system.black }}
|
||||
initial={{ stroke: isFollowed ? Constants.system.blue : Constants.system.black }}
|
||||
animate={{ stroke: isFollowed ? Constants.system.blue : Constants.system.black }}
|
||||
strokeWidth={1.25}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<motion.path
|
||||
d="M4.16668 17.1667C4.62691 17.1667 5.00001 16.7936 5.00001 16.3333C5.00001 15.8731 4.62691 15.5 4.16668 15.5C3.70644 15.5 3.33334 15.8731 3.33334 16.3333C3.33334 16.7936 3.70644 17.1667 4.16668 17.1667Z"
|
||||
initial={{ stroke: isFollowed ? Constants.system.pink : Constants.system.black }}
|
||||
animate={{ stroke: isFollowed ? Constants.system.pink : Constants.system.black }}
|
||||
initial={{ stroke: isFollowed ? Constants.system.blue : Constants.system.black }}
|
||||
animate={{ stroke: isFollowed ? Constants.system.blue : Constants.system.black }}
|
||||
strokeWidth={1.25}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
@ -101,8 +117,20 @@ export default function FollowButton({ onFollow, isFollowed, disabled, followCou
|
||||
<P3
|
||||
as={motion.p}
|
||||
style={{ marginLeft: 4, y: -0.5 }}
|
||||
initial={{ color: isFollowed ? Constants.system.pink : Constants.semantic.textGrayDark }}
|
||||
animate={{ color: isFollowed ? Constants.system.pink : Constants.semantic.textGrayDark }}
|
||||
initial={{
|
||||
color: disabled
|
||||
? Constants.system.gray
|
||||
: isFollowed
|
||||
? Constants.system.blue
|
||||
: Constants.semantic.textGrayDark,
|
||||
}}
|
||||
animate={{
|
||||
color: disabled
|
||||
? Constants.system.gray
|
||||
: isFollowed
|
||||
? Constants.system.blue
|
||||
: Constants.semantic.textGrayDark,
|
||||
}}
|
||||
>
|
||||
{followCount}
|
||||
</P3>
|
||||
|
@ -14,6 +14,8 @@ import { AspectRatio } from "~/components/system";
|
||||
import { P3, H5, P2 } from "~/components/system/components/Typography";
|
||||
import { useMediaQuery, useMounted } from "~/common/hooks";
|
||||
|
||||
import ProfilePhoto from "~/components/core/ProfilePhoto";
|
||||
|
||||
const STYLES_CONTAINER = (theme) => css`
|
||||
position: relative;
|
||||
display: flex;
|
||||
@ -136,7 +138,7 @@ export default function CollectionPreview({ collection, viewer, owner, onAction
|
||||
onClick={follow}
|
||||
isFollowed={isFollowed}
|
||||
followCount={followCount}
|
||||
disabled={collection.ownerId === viewer?.id}
|
||||
disabled={viewer && collection.ownerId === viewer.id}
|
||||
/>
|
||||
<ShareButton user={owner} preview={preview} collection={collection} />
|
||||
</motion.div>
|
||||
@ -231,12 +233,7 @@ function Metrics({ fileCount, owner, isOwner, onAction }) {
|
||||
aria-label={`Visit ${owner.username}'s profile`}
|
||||
title={`Visit ${owner.username}'s profile`}
|
||||
>
|
||||
<img
|
||||
css={STYLES_PROFILE_IMAGE}
|
||||
src={owner.photo}
|
||||
alt={`${owner.username} profile`}
|
||||
onError={(e) => (e.target.src = Constants.profileDefaultPicture)}
|
||||
/>
|
||||
<ProfilePhoto user={owner} style={{ borderRadius: "4px" }} size={16} />
|
||||
</Link>
|
||||
<Link
|
||||
href={`/$/user/${owner.id}`}
|
||||
|
@ -39,7 +39,7 @@ const STYLES_HEADER = css`
|
||||
color: ${Constants.system.black};
|
||||
font-size: ${Constants.typescale.lvl1};
|
||||
font-family: ${Constants.font.semiBold};
|
||||
word-break: break-all;
|
||||
word-break: break-word;
|
||||
`;
|
||||
|
||||
const STYLES_SUB_HEADER = css`
|
||||
|
@ -219,8 +219,18 @@ export default class Profile extends React.Component {
|
||||
index: -1,
|
||||
};
|
||||
|
||||
componentDidMount = () => {
|
||||
if (this.props.page.params?.tab === "subscribed") {
|
||||
this.fetchSocial();
|
||||
}
|
||||
};
|
||||
|
||||
componentDidUpdate = (prevProps) => {
|
||||
if (!this.state.fetched && this.props.page.params !== prevProps.page.params) {
|
||||
if (
|
||||
!this.state.fetched &&
|
||||
this.props.page.params !== prevProps.page.params &&
|
||||
this.props.page.params?.tab === "subscribed"
|
||||
) {
|
||||
this.fetchSocial();
|
||||
}
|
||||
};
|
||||
|
@ -131,7 +131,7 @@ export default class SidebarCreateSlate extends React.Component {
|
||||
onSubmit={this._handleSubmit}
|
||||
descriptionStyle={{ fontSize: "20px !important" }}
|
||||
labelStyle={{ fontSize: "20px" }}
|
||||
maxlength="255"
|
||||
maxLength="255"
|
||||
/>
|
||||
<System.P1
|
||||
style={{
|
||||
@ -162,7 +162,7 @@ export default class SidebarCreateSlate extends React.Component {
|
||||
value={this.state.body}
|
||||
onChange={this._handleChange}
|
||||
onSubmit={this._handleSubmit}
|
||||
maxlength="2000"
|
||||
maxLength="2000"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
@ -169,7 +169,7 @@ export default class SidebarSingleSlateSettings extends React.Component {
|
||||
onSubmit={this._handleSubmit}
|
||||
descriptionStyle={{ fontSize: "20px !important" }}
|
||||
labelStyle={{ fontSize: "20px" }}
|
||||
maxlength="255"
|
||||
maxLength="255"
|
||||
/>
|
||||
<System.P1
|
||||
style={{
|
||||
@ -200,7 +200,7 @@ export default class SidebarSingleSlateSettings extends React.Component {
|
||||
value={this.state.body}
|
||||
onChange={this._handleChange}
|
||||
onSubmit={this._handleSubmit}
|
||||
maxlength="2000"
|
||||
maxLength="2000"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
@ -304,7 +304,7 @@ export const ButtonWarning = (props) => {
|
||||
css={props.transparent ? STYLES_BUTTON_WARNING_TRANSPARENT : STYLES_BUTTON_WARNING}
|
||||
style={{ width: props.full ? "100%" : "auto", ...props.style }}
|
||||
>
|
||||
<LoaderSpinner style={{ height: 16, width: 16 }} />
|
||||
<LoaderSpinner style={{ height: 16, width: 16, color: Constants.system.white }} />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
@ -269,7 +269,7 @@ export class Input extends React.Component {
|
||||
disabled={this.props.disabled}
|
||||
readOnly={this.props.readOnly}
|
||||
required={this.props.required}
|
||||
maxlength={this.props.maxlength}
|
||||
maxLength={this.props.maxLength}
|
||||
style={{
|
||||
width: this.props.copyable || this.props.icon ? "calc(100% - 32px)" : "100%",
|
||||
...this.props.textStyle,
|
||||
|
@ -54,7 +54,7 @@ export class Textarea extends React.Component {
|
||||
name={this.props.name}
|
||||
value={this.props.value}
|
||||
readOnly={this.props.readOnly}
|
||||
maxlength={this.props.maxlength}
|
||||
maxLength={this.props.maxLength}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -17,5 +17,3 @@ export const MIN_ARCHIVE_SIZE_BYTES = 104857600;
|
||||
|
||||
// NOTE(amine): 15 minutes
|
||||
export const TOKEN_EXPIRATION_TIME = 2 * 60 * 60 * 1000;
|
||||
|
||||
export const userPreviewProperties = ["users.id", "users.data", "users.username"];
|
||||
|
@ -11,7 +11,7 @@ export default async (slate) => {
|
||||
const index = query ? query.pop() : null;
|
||||
|
||||
if (index) {
|
||||
if (isPublic) {
|
||||
if (slate.isPublic) {
|
||||
const activityQuery = await DB.insert({
|
||||
ownerId: slate.ownerId,
|
||||
slateId: index.id,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import * as Constants from "~/node_common/constants";
|
||||
import * as Serializers from "~/node_common/serializers";
|
||||
|
||||
import { runQuery } from "~/node_common/data/utilities";
|
||||
|
||||
@ -33,14 +33,14 @@ export default async ({
|
||||
const slateOwnerFields = [
|
||||
"slate_table",
|
||||
"slate_with_objects.*",
|
||||
...Constants.userPreviewProperties,
|
||||
...Serializers.userPreviewProperties,
|
||||
"owner",
|
||||
"slate_with_objects",
|
||||
"users",
|
||||
"slate_with_objects.ownerId",
|
||||
"users.id",
|
||||
];
|
||||
const slateOwnerQuery = `?? as (SELECT ??, json_build_object('id', ??, 'data', ??, 'username', ??) as ?? FROM ?? LEFT JOIN ?? ON ?? = ?? ) `;
|
||||
const slateOwnerQuery = `?? as (SELECT ??, json_build_object('id', ??, 'name', ??, 'username', ??, 'photo', ??) as ?? FROM ?? LEFT JOIN ?? ON ?? = ?? ) `;
|
||||
|
||||
const slateFields = [
|
||||
"slate_with_objects",
|
||||
@ -87,14 +87,14 @@ export default async ({
|
||||
const fileFields = [
|
||||
"files_table",
|
||||
"files.*",
|
||||
...Constants.userPreviewProperties,
|
||||
...Serializers.userPreviewProperties,
|
||||
"owner",
|
||||
"files",
|
||||
"users",
|
||||
"files.ownerId",
|
||||
"users.id",
|
||||
];
|
||||
const fileQuery = `, ?? as (SELECT ??, json_build_object('id', ??, 'data', ??, 'username', ??) as ?? FROM ?? LEFT JOIN ?? on ?? = ??)`;
|
||||
const fileQuery = `, ?? as (SELECT ??, json_build_object('id', ??, 'name', ??, 'username', ??, 'photo', ??) as ?? FROM ?? LEFT JOIN ?? on ?? = ??)`;
|
||||
|
||||
const selectFields = [
|
||||
...slateFields,
|
||||
|
@ -1,5 +1,4 @@
|
||||
import * as Logging from "~/common/logging";
|
||||
import * as Serializers from "~/node_common/serializers";
|
||||
import * as Constants from "~/node_common/constants";
|
||||
|
||||
import { runQuery } from "~/node_common/data/utilities";
|
||||
@ -22,7 +21,7 @@ export default async ({ includeFiles = false, publicOnly = false } = {}) => {
|
||||
let slates;
|
||||
if (publicOnly) {
|
||||
if (includeFiles) {
|
||||
slates = await DB.select(...Serializers.slateProperties, slateFiles())
|
||||
slates = await DB.select("slates.*", slateFiles())
|
||||
.from("slates")
|
||||
.leftJoin("slate_files", "slate_files.slateId", "=", "slates.id")
|
||||
.leftJoin("files", "slate_files.fileId", "=", "files.id")
|
||||
@ -33,7 +32,7 @@ export default async ({ includeFiles = false, publicOnly = false } = {}) => {
|
||||
}
|
||||
} else {
|
||||
if (includeFiles) {
|
||||
slates = await DB.select(...Serializers.slateProperties, slateFiles())
|
||||
slates = await DB.select("slates.*", slateFiles())
|
||||
.from("slates")
|
||||
.leftJoin("slate_files", "slate_files.slateId", "=", "slates.id")
|
||||
.leftJoin("files", "slate_files.fileId", "=", "files.id")
|
||||
|
@ -19,21 +19,27 @@ export default async ({ sanitize = false, includeFiles = false } = {}) => {
|
||||
|
||||
let users;
|
||||
if (includeFiles) {
|
||||
users = await DB.select(...Serializers.userProperties, userFiles())
|
||||
.from("users")
|
||||
.leftJoin("files", "files.ownerId", "users.id");
|
||||
if (sanitize) {
|
||||
users = await DB.select(...Serializers.userPublicProperties, userFiles())
|
||||
.from("users")
|
||||
.leftJoin("files", "files.ownerId", "users.id");
|
||||
} else {
|
||||
users = await DB.select("users.*", userFiles())
|
||||
.from("users")
|
||||
.leftJoin("files", "files.ownerId", "users.id");
|
||||
}
|
||||
} else {
|
||||
users = await DB.select(...Serializers.userProperties).from("users");
|
||||
if (sanitize) {
|
||||
users = await DB.select(...Serializers.userPublicProperties).from("users");
|
||||
} else {
|
||||
users = await DB.select("*").from("users");
|
||||
}
|
||||
}
|
||||
|
||||
if (!users || users.error) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (sanitize) {
|
||||
users = users.map((user) => Serializers.sanitizeUser(user));
|
||||
}
|
||||
|
||||
return JSON.parse(JSON.stringify(users));
|
||||
},
|
||||
errorFn: async (e) => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import * as Constants from "~/node_common/constants";
|
||||
import * as Serializers from "~/node_common/serializers";
|
||||
|
||||
import { runQuery } from "~/node_common/data/utilities";
|
||||
|
||||
@ -9,14 +9,14 @@ export default async ({ earliestTimestamp, latestTimestamp }) => {
|
||||
const slateOwnerFields = [
|
||||
"slate_table",
|
||||
"slate_with_objects.*",
|
||||
...Constants.userPreviewProperties,
|
||||
...Serializers.userPreviewProperties,
|
||||
"owner",
|
||||
"slate_with_objects",
|
||||
"users",
|
||||
"slate_with_objects.ownerId",
|
||||
"users.id",
|
||||
];
|
||||
const slateOwnerQuery = `?? as (SELECT ??, json_build_object('id', ??, 'data', ??, 'username', ??) as ?? FROM ?? LEFT JOIN ?? ON ?? = ?? ) `;
|
||||
const slateOwnerQuery = `?? as (SELECT ??, json_build_object('id', ??, 'name', ??, 'username', ??, 'photo', ??) as ?? FROM ?? LEFT JOIN ?? ON ?? = ?? ) `;
|
||||
|
||||
const slateFields = [
|
||||
"slate_with_objects",
|
||||
@ -63,14 +63,14 @@ export default async ({ earliestTimestamp, latestTimestamp }) => {
|
||||
const fileFields = [
|
||||
"files_table",
|
||||
"files.*",
|
||||
...Constants.userPreviewProperties,
|
||||
...Serializers.userPreviewProperties,
|
||||
"owner",
|
||||
"files",
|
||||
"users",
|
||||
"files.ownerId",
|
||||
"users.id",
|
||||
];
|
||||
const fileQuery = `, ?? as (SELECT ??, json_build_object('id', ??, 'data', ??, 'username', ??) as ?? FROM ?? LEFT JOIN ?? on ?? = ??)`;
|
||||
const fileQuery = `, ?? as (SELECT ??, json_build_object('id', ??, 'name', ??, 'username', ??, 'photo', ??) as ?? FROM ?? LEFT JOIN ?? on ?? = ??)`;
|
||||
|
||||
const selectFields = [
|
||||
...slateFields,
|
||||
|
@ -8,7 +8,7 @@ export default async ({ userId }) => {
|
||||
return await runQuery({
|
||||
label: "GET_FOLLOWERS_BY_USER_ID",
|
||||
queryFn: async (DB) => {
|
||||
const query = await DB.select(...Serializers.userProperties)
|
||||
const query = await DB.select(...Serializers.userPublicProperties)
|
||||
.from("users")
|
||||
.join("subscriptions", "subscriptions.ownerId", "=", "users.id")
|
||||
.where({ "subscriptions.userId": userId })
|
||||
@ -17,12 +17,7 @@ export default async ({ userId }) => {
|
||||
return [];
|
||||
}
|
||||
|
||||
let serialized = [];
|
||||
for (let user of query) {
|
||||
serialized.push(Serializers.sanitizeUser(user));
|
||||
}
|
||||
|
||||
return JSON.parse(JSON.stringify(serialized));
|
||||
return JSON.parse(JSON.stringify(query));
|
||||
},
|
||||
errorFn: async (e) => {
|
||||
Logging.error({
|
||||
|
@ -8,7 +8,7 @@ export default async ({ ownerId }) => {
|
||||
return await runQuery({
|
||||
label: "GET_FOLLOWING_BY_USER_ID",
|
||||
queryFn: async (DB) => {
|
||||
const query = await DB.select(...Serializers.userProperties)
|
||||
const query = await DB.select(...Serializers.userPublicProperties)
|
||||
.from("users")
|
||||
.join("subscriptions", "subscriptions.userId", "=", "users.id")
|
||||
.where({ "subscriptions.ownerId": ownerId })
|
||||
@ -18,12 +18,7 @@ export default async ({ ownerId }) => {
|
||||
return [];
|
||||
}
|
||||
|
||||
let serialized = [];
|
||||
for (let user of query) {
|
||||
serialized.push(Serializers.sanitizeUser(user));
|
||||
}
|
||||
|
||||
return JSON.parse(JSON.stringify(serialized));
|
||||
return JSON.parse(JSON.stringify(query));
|
||||
},
|
||||
errorFn: async (e) => {
|
||||
Logging.error({
|
||||
|
@ -1,6 +1,3 @@
|
||||
import * as Serializers from "~/node_common/serializers";
|
||||
import * as Constants from "~/node_common/constants";
|
||||
|
||||
import { runQuery } from "~/node_common/data/utilities";
|
||||
|
||||
export default async ({ id, includeFiles = false }) => {
|
||||
@ -20,7 +17,7 @@ export default async ({ id, includeFiles = false }) => {
|
||||
let query;
|
||||
|
||||
if (includeFiles) {
|
||||
query = await DB.select(...Serializers.slateProperties, slateFiles())
|
||||
query = await DB.select("slates.*", slateFiles())
|
||||
.from("slates")
|
||||
.leftJoin("slate_files", "slate_files.slateId", "=", "slates.id")
|
||||
.leftJoin("files", "slate_files.fileId", "=", "files.id")
|
||||
@ -28,10 +25,7 @@ export default async ({ id, includeFiles = false }) => {
|
||||
.groupBy("slates.id")
|
||||
.first();
|
||||
} else {
|
||||
query = await DB.select(...Serializers.slateProperties)
|
||||
.from("slates")
|
||||
.where({ id })
|
||||
.first();
|
||||
query = await DB.select("*").from("slates").where({ id }).first();
|
||||
}
|
||||
|
||||
if (!query || query.error) {
|
||||
|
@ -1,6 +1,3 @@
|
||||
import * as Serializers from "~/node_common/serializers";
|
||||
import * as Constants from "~/node_common/constants";
|
||||
|
||||
import { runQuery } from "~/node_common/data/utilities";
|
||||
|
||||
export default async ({ slatename, ownerId, username, includeFiles = false }) => {
|
||||
@ -32,7 +29,7 @@ export default async ({ slatename, ownerId, username, includeFiles = false }) =>
|
||||
let query;
|
||||
|
||||
if (includeFiles) {
|
||||
query = await DB.select(...Serializers.slateProperties, slateFiles())
|
||||
query = await DB.select("slates.*", slateFiles())
|
||||
.from("slates")
|
||||
.leftJoin("slate_files", "slate_files.slateId", "=", "slates.id")
|
||||
.leftJoin("files", "slate_files.fileId", "=", "files.id")
|
||||
@ -40,10 +37,7 @@ export default async ({ slatename, ownerId, username, includeFiles = false }) =>
|
||||
.groupBy("slates.id")
|
||||
.first();
|
||||
} else {
|
||||
query = await DB.select(...Serializers.slateProperties)
|
||||
.from("slates")
|
||||
.where({ slatename, ownerId: id })
|
||||
.first();
|
||||
query = await DB.select("*").from("slates").where({ slatename, ownerId: id }).first();
|
||||
}
|
||||
|
||||
if (!query || query.error) {
|
||||
|
@ -1,6 +1,3 @@
|
||||
import * as Constants from "~/node_common/constants";
|
||||
import * as Serializers from "~/node_common/serializers";
|
||||
|
||||
import { runQuery } from "~/node_common/data/utilities";
|
||||
|
||||
/**
|
||||
@ -11,7 +8,7 @@ export default async ({ slateId, cids }) => {
|
||||
return await runQuery({
|
||||
label: "GET_SLATE_FILES_BY_CID",
|
||||
queryFn: async (DB) => {
|
||||
const query = await DB.select(...Serializers.fileProperties)
|
||||
const query = await DB.select("files.*")
|
||||
.from("files")
|
||||
.join("slate_files", "slate_files.fileId", "=", "files.id")
|
||||
.where("slate_files.slateId", slateId)
|
||||
|
@ -1,6 +1,3 @@
|
||||
import * as Serializers from "~/node_common/serializers";
|
||||
import * as Constants from "~/node_common/constants";
|
||||
|
||||
import { runQuery } from "~/node_common/data/utilities";
|
||||
|
||||
export default async ({ ids, includeFiles = false }) => {
|
||||
@ -20,16 +17,14 @@ export default async ({ ids, includeFiles = false }) => {
|
||||
]);
|
||||
|
||||
if (includeFiles) {
|
||||
query = await DB.select(...Serializers.slateProperties, slateFiles())
|
||||
query = await DB.select("slates.*", slateFiles())
|
||||
.from("slates")
|
||||
.leftJoin("slate_files", "slate_files.slateId", "=", "slates.id")
|
||||
.leftJoin("files", "slate_files.fileId", "=", "files.id")
|
||||
.whereIn("slates.id", ids)
|
||||
.groupBy("slates.id");
|
||||
} else {
|
||||
query = await DB.select(...Serializers.slateProperties)
|
||||
.from("slates")
|
||||
.whereIn("id", ids);
|
||||
query = await DB.select("*").from("slates").whereIn("id", ids);
|
||||
}
|
||||
|
||||
if (!query || query.error) {
|
||||
|
@ -1,5 +1,3 @@
|
||||
import * as Serializers from "~/node_common/serializers";
|
||||
import * as Constants from "~/node_common/constants";
|
||||
import * as Logging from "~/common/logging";
|
||||
|
||||
import { runQuery } from "~/node_common/data/utilities";
|
||||
@ -28,7 +26,7 @@ export default async ({ ownerId, includeFiles = false, publicOnly = false }) =>
|
||||
let query;
|
||||
if (includeFiles) {
|
||||
if (publicOnly) {
|
||||
query = await DB.select(...Serializers.slateProperties, slateFiles())
|
||||
query = await DB.select("slates.*", slateFiles())
|
||||
.from("slates")
|
||||
.leftJoin("slate_files", "slate_files.slateId", "=", "slates.id")
|
||||
.leftJoin("files", "slate_files.fileId", "=", "files.id")
|
||||
@ -36,7 +34,7 @@ export default async ({ ownerId, includeFiles = false, publicOnly = false }) =>
|
||||
.groupBy("slates.id")
|
||||
.orderBy("slates.updatedAt", "desc");
|
||||
} else {
|
||||
query = await DB.select(...Serializers.slateProperties, slateFiles())
|
||||
query = await DB.select("slates.*", slateFiles())
|
||||
.from("slates")
|
||||
.leftJoin("slate_files", "slate_files.slateId", "=", "slates.id")
|
||||
.leftJoin("files", "slate_files.fileId", "=", "files.id")
|
||||
@ -46,14 +44,14 @@ export default async ({ ownerId, includeFiles = false, publicOnly = false }) =>
|
||||
}
|
||||
} else {
|
||||
if (publicOnly) {
|
||||
query = await DB.select(...Serializers.slateProperties)
|
||||
query = await DB.select("*")
|
||||
.from("slates")
|
||||
.where({ "slates.ownerId": ownerId, "slates.isPublic": true })
|
||||
.where({ ownerId: ownerId, isPublic: true })
|
||||
.orderBy("updatedAt", "desc");
|
||||
} else {
|
||||
query = await DB.select(...Serializers.slateProperties)
|
||||
query = await DB.select("*")
|
||||
.from("slates")
|
||||
.where({ "slates.ownerId": ownerId })
|
||||
.where({ ownerId: ownerId })
|
||||
.orderBy("updatedAt", "desc");
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ export default async ({ slateId }) => {
|
||||
return await runQuery({
|
||||
label: "GET_SUBSCRIBERS_BY_SLATE_ID",
|
||||
queryFn: async (DB) => {
|
||||
const query = await DB.select(...Serializers.userProperties)
|
||||
const query = await DB.select(...Serializers.userPublicProperties)
|
||||
.from("users")
|
||||
.join("subscriptions", "subscriptions.ownerId", "=", "users.id")
|
||||
.where({ "subscriptions.slateId": slateId })
|
||||
@ -18,12 +18,7 @@ export default async ({ slateId }) => {
|
||||
return [];
|
||||
}
|
||||
|
||||
let serialized = [];
|
||||
for (let user of query) {
|
||||
serialized.push(Serializers.sanitizeUser(user));
|
||||
}
|
||||
|
||||
return JSON.parse(JSON.stringify(serialized));
|
||||
return JSON.parse(JSON.stringify(query));
|
||||
},
|
||||
errorFn: async (e) => {
|
||||
Logging.error({
|
||||
|
@ -1,5 +1,4 @@
|
||||
import * as Serializers from "~/node_common/serializers";
|
||||
import * as Constants from "~/node_common/constants";
|
||||
import * as Logging from "~/common/logging";
|
||||
|
||||
import { runQuery } from "~/node_common/data/utilities";
|
||||
@ -11,9 +10,9 @@ export default async ({ ownerId }) => {
|
||||
// const slateFiles = () =>
|
||||
// DB.raw("json_agg(?? order by ?? asc) as ??", ["files", "slate_files.createdAt", "objects"]);
|
||||
|
||||
const ownerQueryFields = [...Constants.userPreviewProperties, "owner"];
|
||||
const ownerQueryFields = [...Serializers.userPreviewProperties, "owner"];
|
||||
const ownerQuery = DB.raw(
|
||||
`json_build_object('id', ??, 'data', ??, 'username', ??) as ??`,
|
||||
`json_build_object('id', ??, 'name', ??, 'username', ??, 'photo', ??) as ??`,
|
||||
ownerQueryFields
|
||||
);
|
||||
|
||||
@ -27,7 +26,7 @@ export default async ({ ownerId }) => {
|
||||
|
||||
const query = await DB.with("slates", (db) =>
|
||||
db
|
||||
.select(...Serializers.slateProperties, slateFiles())
|
||||
.select("slates.*", slateFiles())
|
||||
.from("slates")
|
||||
.join("subscriptions", "subscriptions.slateId", "=", "slates.id")
|
||||
.join("slate_files", "slate_files.slateId", "=", "slates.id")
|
||||
@ -36,7 +35,7 @@ export default async ({ ownerId }) => {
|
||||
// .orderBy("subscriptions.createdAt", "desc");
|
||||
.groupBy("slates.id")
|
||||
)
|
||||
.select(...Serializers.slateProperties, "objects", ownerQuery)
|
||||
.select("slates.*", "objects", ownerQuery)
|
||||
.from("slates")
|
||||
.join("users", "slates.ownerId", "users.id");
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import * as Serializers from "~/node_common/serializers";
|
||||
|
||||
import { runQuery } from "~/node_common/data/utilities";
|
||||
|
||||
//NOTE(toast): should only be used for checking if an email is taken
|
||||
@ -7,16 +8,20 @@ export default async ({ email, sanitize = false }) => {
|
||||
return await runQuery({
|
||||
label: "GET_USER_BY_EMAIL",
|
||||
queryFn: async (DB) => {
|
||||
let query = await DB.select("*").from("users").where({ email }).first();
|
||||
let query;
|
||||
if (sanitize) {
|
||||
query = await DB.select(...Serializers.userPublicProperties)
|
||||
.from("users")
|
||||
.where({ email })
|
||||
.first();
|
||||
} else {
|
||||
query = await DB.select("*").from("users").where({ email }).first();
|
||||
}
|
||||
|
||||
if (!query || query.error) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (sanitize) {
|
||||
query = Serializers.sanitizeUser(query);
|
||||
}
|
||||
|
||||
return JSON.parse(JSON.stringify(query));
|
||||
},
|
||||
errorFn: async (e) => {
|
||||
|
@ -15,13 +15,23 @@ export default async ({ id, sanitize = false, includeFiles = false, publicOnly =
|
||||
// const userFiles = () =>
|
||||
// DB.raw("json_agg(?? order by ?? desc) as ??", ["files", "files.createdAt", "library"]);
|
||||
|
||||
const userFiles = () =>
|
||||
DB.raw(
|
||||
"coalesce(json_agg(?? order by ?? desc) filter (where ?? is not null), '[]') as ??",
|
||||
["files", "files.createdAt", "files.id", "library"]
|
||||
);
|
||||
// const userFiles = () =>
|
||||
// DB.raw(
|
||||
// "coalesce(json_agg(?? order by ?? desc) filter (where ?? is not null), '[]') as ??",
|
||||
// ["files", "files.createdAt", "files.id", "library"]
|
||||
// );
|
||||
|
||||
let query;
|
||||
|
||||
if (sanitize) {
|
||||
query = await DB.select(...Serializers.userPublicProperties)
|
||||
.from("users")
|
||||
.where({ id })
|
||||
.first();
|
||||
} else {
|
||||
query = await DB.select("*").from("users").where({ id }).first();
|
||||
}
|
||||
|
||||
if (includeFiles) {
|
||||
if (publicOnly) {
|
||||
//TODO(martina): fix this so can be done in one query. Right now, it's duplicating files for each slate_files entry. Need to do distinct on file.id for the json agg
|
||||
@ -41,9 +51,7 @@ export default async ({ id, sanitize = false, includeFiles = false, publicOnly =
|
||||
// .groupBy("users.id")
|
||||
// .first();
|
||||
|
||||
query = await DB.select("*").from("users").where({ id }).first();
|
||||
|
||||
let library = await DB.select(...Serializers.fileProperties)
|
||||
let library = await DB.select("files.*")
|
||||
.from("files")
|
||||
.leftJoin("slate_files", "slate_files.fileId", "=", "files.id")
|
||||
.leftJoin("slates", "slate_files.slateId", "=", "slates.id")
|
||||
@ -62,19 +70,21 @@ export default async ({ id, sanitize = false, includeFiles = false, publicOnly =
|
||||
|
||||
query.library = library;
|
||||
} else {
|
||||
query = await DB.select(...Serializers.userProperties, userFiles())
|
||||
.from("users")
|
||||
.where({ "users.id": id })
|
||||
.leftJoin("files", "files.ownerId", "users.id")
|
||||
.groupBy("users.id")
|
||||
.first();
|
||||
}
|
||||
} else {
|
||||
query = await DB.select("*").from("users").where({ id }).first();
|
||||
}
|
||||
let library = await DB.select("*")
|
||||
.from("files")
|
||||
.where({ ownerId: id })
|
||||
.orderBy("createdAt", "desc")
|
||||
.groupBy("id");
|
||||
|
||||
if (sanitize) {
|
||||
query = Serializers.sanitizeUser(query);
|
||||
query.library = library;
|
||||
|
||||
// query = await DB.select("users.*", userFiles())
|
||||
// .from("users")
|
||||
// .where({ "users.id": id })
|
||||
// .leftJoin("files", "files.ownerId", "users.id")
|
||||
// .groupBy("users.id")
|
||||
// .first();
|
||||
}
|
||||
}
|
||||
|
||||
if (!query || query.error) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import * as Serializers from "~/node_common/serializers";
|
||||
|
||||
import { runQuery } from "~/node_common/data/utilities";
|
||||
|
||||
//NOTE(toast): should only be used for checking if an email is taken
|
||||
@ -7,14 +8,15 @@ export default async ({ twitterId }) => {
|
||||
return await runQuery({
|
||||
label: "GET_USER_BY_TWITTER_ID",
|
||||
queryFn: async (DB) => {
|
||||
let query = await DB.select("*").from("users").where({ twitterId }).first();
|
||||
let query = await DB.select(...Serializers.userPublicProperties)
|
||||
.from("users")
|
||||
.where({ twitterId })
|
||||
.first();
|
||||
|
||||
if (!query || query.error) {
|
||||
return null;
|
||||
}
|
||||
|
||||
query = Serializers.sanitizeUser(query);
|
||||
|
||||
return JSON.parse(JSON.stringify(query));
|
||||
},
|
||||
errorFn: async (e) => {
|
||||
|
@ -7,18 +7,26 @@ export default async ({ username, sanitize = false, includeFiles = false, public
|
||||
return await runQuery({
|
||||
label: "GET_USER_BY_USERNAME",
|
||||
queryFn: async (DB) => {
|
||||
// const userFiles = () =>
|
||||
// DB.raw("json_agg(?? order by ?? desc) as ??", ["files", "files.createdAt", "library"]);
|
||||
|
||||
const userFiles = () =>
|
||||
DB.raw(
|
||||
"coalesce(json_agg(?? order by ?? desc) filter (where ?? is not null), '[]') as ??",
|
||||
["files", "files.createdAt", "files.id", "library"]
|
||||
);
|
||||
|
||||
let query;
|
||||
|
||||
if (sanitize) {
|
||||
query = await DB.select(...Serializers.userPublicProperties)
|
||||
.from("users")
|
||||
.where({ username })
|
||||
.first();
|
||||
} else {
|
||||
query = await DB.select("*").from("users").where({ username }).first();
|
||||
}
|
||||
|
||||
const id = query?.id;
|
||||
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (includeFiles) {
|
||||
if (publicOnly) {
|
||||
//TODO(martina): fix this so can be done in one query. Right now, it's duplicating files for each slate_files entry. Need to do distinct on file.id for the json agg
|
||||
// query = await DB.select(
|
||||
// "users.id",
|
||||
// "users.username",
|
||||
@ -30,82 +38,51 @@ export default async ({ username, sanitize = false, includeFiles = false, public
|
||||
// .join("files", "files.ownerId", "users.id")
|
||||
// .join("slate_files", "files.id", "=", "slate_files.fileId")
|
||||
// .join("slates", "slates.id", "=", "slate_files.slateId")
|
||||
// .where({ "users.username": username, "files.isPublic": true })
|
||||
// .orWhere({ "users.username": username, "slates.isPublic": true })
|
||||
// .groupBy("users.id");
|
||||
// .first();
|
||||
|
||||
// let subquery = () =>
|
||||
// DB.select(
|
||||
// "files.id",
|
||||
// "files.ownerId",
|
||||
// "files.cid",
|
||||
// "files.isPublic",
|
||||
// "files.filename",
|
||||
// "files.data"
|
||||
// )
|
||||
// .from("files")
|
||||
// .join("slate_files", "files.id", "=", "slate_files.fileId")
|
||||
// .join("slates", "slates.id", "=", "slate_files.slateId")
|
||||
// .where({ "files.isPublic": true })
|
||||
// .orWhere({ "slates.isPublic": true })
|
||||
// .as("files");
|
||||
|
||||
// query = await DB.select(
|
||||
// "users.id",
|
||||
// "users.username",
|
||||
// "users.data",
|
||||
// "users.email",
|
||||
// userFiles()
|
||||
// )
|
||||
// .from("users")
|
||||
// .join(subquery(), "publicFiles.ownerId", "=", "users.id")
|
||||
// .where({ "users.username": username })
|
||||
// .where({ "users.id": id, "files.isPublic": true })
|
||||
// .orWhere({ "users.id": id, "slates.isPublic": true })
|
||||
// .groupBy("users.id")
|
||||
// .first();
|
||||
query = await DB.select("*").from("users").where({ username }).first();
|
||||
|
||||
const id = query?.id;
|
||||
let library = await DB.select("files.*")
|
||||
.from("files")
|
||||
.leftJoin("slate_files", "slate_files.fileId", "=", "files.id")
|
||||
.leftJoin("slates", "slate_files.slateId", "=", "slates.id")
|
||||
.whereRaw("?? = ? and (?? = ? or ?? = ?)", [
|
||||
"files.ownerId",
|
||||
id,
|
||||
"files.isPublic",
|
||||
true,
|
||||
"slates.isPublic",
|
||||
true,
|
||||
])
|
||||
// .where({ "files.ownerId": id, "slates.isPublic": true })
|
||||
// .orWhere({ "files.ownerId": id, "files.isPublic": true })
|
||||
.orderBy("files.createdAt", "desc")
|
||||
.groupBy("files.id");
|
||||
|
||||
if (id) {
|
||||
let library = await DB.select(...Serializers.fileProperties)
|
||||
.from("files")
|
||||
.leftJoin("slate_files", "slate_files.fileId", "=", "files.id")
|
||||
.leftJoin("slates", "slate_files.slateId", "=", "slates.id")
|
||||
// .where({ "files.ownerId": id, "slates.isPublic": true })
|
||||
// .orWhere({ "files.ownerId": id, "files.isPublic": true })
|
||||
.whereRaw("?? = ? and (?? = ? or ?? = ?)", [
|
||||
"files.ownerId",
|
||||
id,
|
||||
"files.isPublic",
|
||||
true,
|
||||
"slates.isPublic",
|
||||
true,
|
||||
])
|
||||
.orderBy("files.createdAt", "desc")
|
||||
.groupBy("files.id");
|
||||
|
||||
query.library = library;
|
||||
}
|
||||
query.library = library;
|
||||
} else {
|
||||
query = await DB.select(...Serializers.userProperties, userFiles())
|
||||
.from("users")
|
||||
.where({ "users.username": username })
|
||||
.leftJoin("files", "files.ownerId", "users.id")
|
||||
.first();
|
||||
let library = await DB.select("*")
|
||||
.from("files")
|
||||
.where({ ownerId: id })
|
||||
.orderBy("createdAt", "desc")
|
||||
.groupBy("id");
|
||||
|
||||
query.library = library;
|
||||
|
||||
// query = await DB.select("users.*", userFiles())
|
||||
// .from("users")
|
||||
// .where({ "users.id": id })
|
||||
// .leftJoin("files", "files.ownerId", "users.id")
|
||||
// .groupBy("users.id")
|
||||
// .first();
|
||||
}
|
||||
} else {
|
||||
query = await DB.select("*").from("users").where({ username }).first();
|
||||
}
|
||||
|
||||
if (!query || query.error) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (sanitize) {
|
||||
query = Serializers.sanitizeUser(query);
|
||||
}
|
||||
|
||||
return JSON.parse(JSON.stringify(query));
|
||||
},
|
||||
errorFn: async (e) => {
|
||||
|
@ -1,55 +0,0 @@
|
||||
import { runQuery } from "~/node_common/data/utilities";
|
||||
|
||||
export default async ({ id, ownerId, isPublic }) => {
|
||||
return await runQuery({
|
||||
label: "UPDATE_FILE_PRIVACY",
|
||||
queryFn: async (DB) => {
|
||||
if (isPublic === false) {
|
||||
//NOTE(martina): if making a file private, remove any activity items involving it
|
||||
const activity = await DB("activity").where("fileId", id).update({ ignore: true });
|
||||
|
||||
const repostedSlateFiles = await DB.from("slate_files")
|
||||
.whereIn("id", function () {
|
||||
this.select("slate_files.id")
|
||||
.from("slate_files")
|
||||
.join("slates", "slates.id", "=", "slate_files.slateId")
|
||||
.where({ "slate_files.fileId": id })
|
||||
.whereNot("slates.ownerId", "=", ownerId);
|
||||
})
|
||||
.del();
|
||||
// .update({ fileId: null })
|
||||
|
||||
//NOTE(martina): and remove it from any of the user's public slates
|
||||
const deletedSlateFiles = await DB.from("slate_files")
|
||||
.whereIn("id", function () {
|
||||
this.select("slate_files.id")
|
||||
.from("slate_files")
|
||||
.join("slates", "slates.id", "=", "slate_files.slateId")
|
||||
.where({
|
||||
"slates.isPublic": true,
|
||||
"slates.ownerId": ownerId,
|
||||
"slate_files.fileId": id,
|
||||
});
|
||||
})
|
||||
.del()
|
||||
.returning("slateId");
|
||||
|
||||
//NOTE(martina): then decrement the fileCount for those slates
|
||||
const slatesSummaryQuery = await DB.from("slates")
|
||||
.whereIn("id", deletedSlateFiles)
|
||||
.decrement("fileCount", 1);
|
||||
}
|
||||
|
||||
const response = await DB.from("files").where("id", id).update({ isPublic }).returning("*");
|
||||
|
||||
const index = response ? response.pop() : null;
|
||||
return JSON.parse(JSON.stringify(index));
|
||||
},
|
||||
errorFn: async (e) => {
|
||||
return {
|
||||
error: true,
|
||||
decorator: "UPDATE_FILE_PRIVACY",
|
||||
};
|
||||
},
|
||||
});
|
||||
};
|
@ -1,43 +0,0 @@
|
||||
import * as Logging from "~/common/logging";
|
||||
|
||||
import { runQuery } from "~/node_common/data/utilities";
|
||||
|
||||
//NOTE(martina): this method is specifically for making *multiple* files from one owner *public*. It will filter out the already public files
|
||||
export default async ({ ids, ownerId }) => {
|
||||
return await runQuery({
|
||||
label: "UPDATE_FILES_PUBLIC",
|
||||
queryFn: async (DB) => {
|
||||
let privateFiles = await DB.select("id")
|
||||
.from("files")
|
||||
.whereIn("id", ids)
|
||||
.where("isPublic", false);
|
||||
if (!privateFiles?.length) {
|
||||
return [];
|
||||
}
|
||||
let privateIds = privateFiles.map((file) => file.id);
|
||||
|
||||
let activityItems = [];
|
||||
for (let id of privateIds) {
|
||||
activityItems.push({
|
||||
ownerId,
|
||||
fileId: id,
|
||||
type: "FILE_VISIBLE",
|
||||
});
|
||||
}
|
||||
let activityQuery = await DB.insert(activityItems).into("activity");
|
||||
|
||||
const response = await DB.from("files")
|
||||
.whereIn("id", privateIds)
|
||||
.update({ isPublic: true })
|
||||
.returning("*");
|
||||
|
||||
return JSON.parse(JSON.stringify(response));
|
||||
},
|
||||
errorFn: async (e) => {
|
||||
return {
|
||||
error: true,
|
||||
decorator: "UPDATE_FILES_PUBLIC",
|
||||
};
|
||||
},
|
||||
});
|
||||
};
|
@ -1,3 +1,31 @@
|
||||
// //NOTE(martina): clean the object before adding it to the database
|
||||
// export const cleanUser = (user) => {
|
||||
// return {
|
||||
// id: user.id,
|
||||
// createdAt: user.createdAt,
|
||||
// lastActive: user.lastActive,
|
||||
// username: user.username,
|
||||
// password: user.password,
|
||||
// salt: user.salt,
|
||||
// email: user.email,
|
||||
// followerCount: user.followerCount,
|
||||
// slateCount: user.slateCount,
|
||||
// twitterId: user.twitterId,
|
||||
// authVersion: user.authVersion,
|
||||
// revertedVersion: user.revertedVersion,
|
||||
// body: user.body,
|
||||
// photo: user.photo,
|
||||
// name: user.name,
|
||||
// twitterUsername: user.twitterUsername,
|
||||
// twitterVerified: user.twitterVerified,
|
||||
// textileToken: user.textileToken,
|
||||
// settingsDealAutoApprove: user.settingsDealAutoApprove,
|
||||
// allowAutomaticDataStorage: user.allowAutomaticDataStorage,
|
||||
// allowEncryptedDataStorage: user.allowEncryptedDataStorage,
|
||||
// onboarding: user.onboarding,
|
||||
// };
|
||||
// };
|
||||
|
||||
//NOTE(martina): add a variable to sanitizeUser if it should be sent to the front end. Otherwise, it will be filtered out
|
||||
|
||||
export const sanitizeUser = (user) => {
|
||||
@ -18,23 +46,8 @@ export const sanitizeUser = (user) => {
|
||||
};
|
||||
};
|
||||
|
||||
//NOTE(martina): list of the properties of the tables that should be returned by db queries. Convenience so we don't have to write these out each time and update in multiple places
|
||||
export const slateProperties = [
|
||||
"slates.id",
|
||||
"slates.ownerId",
|
||||
"slates.createdAt",
|
||||
"slates.updatedAt",
|
||||
"slates.slatename",
|
||||
"slates.body",
|
||||
"slates.name",
|
||||
"slates.preview",
|
||||
"slates.isPublic",
|
||||
"slates.subscriberCount",
|
||||
"slates.fileCount",
|
||||
];
|
||||
|
||||
//NOTE(martina): the user properties list filters out sensitive information
|
||||
export const userProperties = [
|
||||
//NOTE(martina): the user public properties list filters out sensitive information
|
||||
export const userPublicProperties = [
|
||||
"users.id",
|
||||
"users.createdAt",
|
||||
"users.lastActive",
|
||||
@ -48,34 +61,5 @@ export const userProperties = [
|
||||
"users.twitterVerified",
|
||||
];
|
||||
|
||||
export const fileProperties = [
|
||||
"files.id",
|
||||
"files.ownerId",
|
||||
"files.createdAt",
|
||||
"files.cid",
|
||||
"files.isPublic",
|
||||
"files.filename",
|
||||
"files.name",
|
||||
"files.body",
|
||||
"files.size",
|
||||
"files.type",
|
||||
"files.blurhash",
|
||||
"files.data",
|
||||
"files.source",
|
||||
"files.author",
|
||||
"files.coverImage",
|
||||
"files.downloadCount",
|
||||
"files.saveCount",
|
||||
"files.isLink",
|
||||
"files.url",
|
||||
"files.linkName",
|
||||
"files.linkBody",
|
||||
"files.linkAuthor",
|
||||
"files.linkSource",
|
||||
"files.linkDomain",
|
||||
"files.linkImage",
|
||||
"files.linkFavicon",
|
||||
"files.linkHtml",
|
||||
"files.linkIFrameAllowed",
|
||||
"files.tags",
|
||||
];
|
||||
//NOTE(martina): the user preview properties list contains the minimal info needed to preview the owner of a file or slate
|
||||
export const userPreviewProperties = ["users.id", "users.name", "users.username", "users.photo"];
|
||||
|
@ -110,12 +110,12 @@ export default async (req, res) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (targetUser && !existingResponse) {
|
||||
if (targetUser) {
|
||||
ViewerManager.hydratePartial(id, { following: true });
|
||||
Monitor.subscribeUser({ user, targetUser });
|
||||
}
|
||||
|
||||
if (targetSlate && !existingResponse) {
|
||||
if (targetSlate) {
|
||||
ViewerManager.hydratePartial(id, { subscriptions: true });
|
||||
Monitor.subscribeSlate({ user, targetSlate });
|
||||
}
|
||||
|
@ -16,42 +16,77 @@ export default async (req, res) => {
|
||||
if (!userInfo) return;
|
||||
const { id, user } = userInfo;
|
||||
|
||||
let updates = req.body.data;
|
||||
let updates = req.body.data.user;
|
||||
|
||||
if (updates.username && updates.username !== user.username) {
|
||||
if (!Validations.username(req.body.data.username)) {
|
||||
return res.status(400).send({
|
||||
decorator: "SERVER_USER_UPDATE_INVALID_USERNAME",
|
||||
error: true,
|
||||
if (updates) {
|
||||
if (updates.username && updates.username !== user.username) {
|
||||
if (!Validations.username(updates.username)) {
|
||||
return res.status(400).send({
|
||||
decorator: "SERVER_USER_UPDATE_INVALID_USERNAME",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
const existing = await Data.getUserByUsername({
|
||||
username: updates.username.toLowerCase(),
|
||||
});
|
||||
|
||||
if (existing && existing.id !== id) {
|
||||
return res
|
||||
.status(500)
|
||||
.send({ decorator: "SERVER_USER_UPDATE_USERNAME_IS_TAKEN", error: true });
|
||||
}
|
||||
}
|
||||
|
||||
const existing = await Data.getUserByUsername({
|
||||
username: req.body.data.username.toLowerCase(),
|
||||
});
|
||||
if (updates.email && updates.email !== user.email) {
|
||||
if (!Validations.email(updates.email)) {
|
||||
return res.status(400).send({
|
||||
decorator: "SERVER_USER_UPDATE_INVALID_EMAIL",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (existing && existing.id !== id) {
|
||||
return res
|
||||
.status(500)
|
||||
.send({ decorator: "SERVER_USER_UPDATE_USERNAME_IS_TAKEN", error: true });
|
||||
}
|
||||
}
|
||||
|
||||
if (updates.email && updates.email !== user.email) {
|
||||
if (!Validations.email(req.body.data.email)) {
|
||||
return res.status(400).send({
|
||||
decorator: "SERVER_USER_UPDATE_INVALID_EMAIL",
|
||||
error: true,
|
||||
const existing = await Data.getUserByEmail({
|
||||
email: updates.email.toLowerCase(),
|
||||
});
|
||||
|
||||
if (existing && existing.id !== id) {
|
||||
return res.status(500).send({ decorator: "SERVER_USER_UPDATE_EMAIL", error: true });
|
||||
}
|
||||
}
|
||||
|
||||
const existing = await Data.getUserByEmail({
|
||||
email: req.body.data.email.toLowerCase(),
|
||||
});
|
||||
if (req.body.data.type === "CHANGE_PASSWORD" && updates.password) {
|
||||
if (!Validations.password(updates.password)) {
|
||||
return res
|
||||
.status(500)
|
||||
.send({ decorator: "SERVER_USER_UPDATE_INVALID_PASSWORD", error: true });
|
||||
}
|
||||
|
||||
if (existing && existing.id !== id) {
|
||||
return res.status(500).send({ decorator: "SERVER_USER_UPDATE_EMAIL", error: true });
|
||||
const rounds = Number(Environment.LOCAL_PASSWORD_ROUNDS);
|
||||
const salt = await BCrypt.genSalt(rounds);
|
||||
const hash = await Utilities.encryptPassword(updates.password, salt);
|
||||
|
||||
updates.salt = salt;
|
||||
updates.password = hash;
|
||||
}
|
||||
|
||||
if (updates.body && updates.body.length > 2000) {
|
||||
return res.status(400).send({ decorator: "SERVER_USER_UPDATE_MAX_BODY_LENGTH", error: true });
|
||||
}
|
||||
|
||||
let unsafeResponse = await Data.updateUserById({ id, ...updates });
|
||||
|
||||
if (unsafeResponse && !unsafeResponse.error) {
|
||||
if (
|
||||
user.username !== unsafeResponse.username ||
|
||||
user.name !== unsafeResponse.name ||
|
||||
user.photo !== unsafeResponse.photo
|
||||
) {
|
||||
SearchManager.updateUser(unsafeResponse, "EDIT");
|
||||
}
|
||||
}
|
||||
|
||||
ViewerManager.hydratePartial(id, { viewer: true });
|
||||
}
|
||||
|
||||
if (req.body.data.type === "SAVE_DEFAULT_ARCHIVE_CONFIG") {
|
||||
@ -95,38 +130,5 @@ export default async (req, res) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (req.body.data.type === "CHANGE_PASSWORD" && req.body.data.password) {
|
||||
if (!Validations.password(req.body.data.password)) {
|
||||
return res
|
||||
.status(500)
|
||||
.send({ decorator: "SERVER_USER_UPDATE_INVALID_PASSWORD", error: true });
|
||||
}
|
||||
|
||||
const rounds = Number(Environment.LOCAL_PASSWORD_ROUNDS);
|
||||
const salt = await BCrypt.genSalt(rounds);
|
||||
const hash = await Utilities.encryptPassword(req.body.data.password, salt);
|
||||
|
||||
updates.salt = salt;
|
||||
updates.password = hash;
|
||||
}
|
||||
|
||||
if (updates.body && updates.body.length > 2000) {
|
||||
return res.status(400).send({ decorator: "SERVER_USER_UPDATE_MAX_BODY_LENGTH", error: true });
|
||||
}
|
||||
|
||||
let unsafeResponse = await Data.updateUserById({ id, ...updates });
|
||||
|
||||
if (unsafeResponse && !unsafeResponse.error) {
|
||||
if (
|
||||
user.username !== unsafeResponse.username ||
|
||||
user.name !== unsafeResponse.name ||
|
||||
user.photo !== unsafeResponse.photo
|
||||
) {
|
||||
SearchManager.updateUser(unsafeResponse, "EDIT");
|
||||
}
|
||||
}
|
||||
|
||||
ViewerManager.hydratePartial(id, { viewer: true });
|
||||
|
||||
return res.status(200).send({ decorator: "SERVER_USER_UPDATE" });
|
||||
};
|
||||
|
@ -73,8 +73,10 @@ export default class SceneArchive extends React.Component {
|
||||
this.setState({ changingFilecoin: true });
|
||||
|
||||
await Actions.updateViewer({
|
||||
allowAutomaticDataStorage: this.state.allowAutomaticDataStorage,
|
||||
allowEncryptedDataStorage: this.state.allowEncryptedDataStorage,
|
||||
user: {
|
||||
allowAutomaticDataStorage: this.state.allowAutomaticDataStorage,
|
||||
allowEncryptedDataStorage: this.state.allowEncryptedDataStorage,
|
||||
},
|
||||
});
|
||||
|
||||
this.setState({ changingFilecoin: false });
|
||||
|
@ -71,7 +71,9 @@ export default class SceneEditAccount extends React.Component {
|
||||
const cid = file.cid;
|
||||
const url = Strings.getURLfromCID(cid);
|
||||
let updateResponse = await Actions.updateViewer({
|
||||
photo: Strings.getURLfromCID(cid),
|
||||
user: {
|
||||
photo: Strings.getURLfromCID(cid),
|
||||
},
|
||||
});
|
||||
|
||||
Events.hasError(updateResponse);
|
||||
@ -82,8 +84,10 @@ export default class SceneEditAccount extends React.Component {
|
||||
this.setState({ changingFilecoin: true });
|
||||
|
||||
let response = await Actions.updateViewer({
|
||||
allowAutomaticDataStorage: this.state.allowAutomaticDataStorage,
|
||||
allowEncryptedDataStorage: this.state.allowEncryptedDataStorage,
|
||||
user: {
|
||||
allowAutomaticDataStorage: this.state.allowAutomaticDataStorage,
|
||||
allowEncryptedDataStorage: this.state.allowEncryptedDataStorage,
|
||||
},
|
||||
});
|
||||
|
||||
Events.hasError(response);
|
||||
@ -106,10 +110,12 @@ export default class SceneEditAccount extends React.Component {
|
||||
this.setState({ savingNameBio: true });
|
||||
|
||||
let response = await Actions.updateViewer({
|
||||
username: this.state.username,
|
||||
photo: this.state.photo,
|
||||
body: this.state.body,
|
||||
name: this.state.name,
|
||||
user: {
|
||||
username: this.state.username,
|
||||
photo: this.state.photo,
|
||||
body: this.state.body,
|
||||
name: this.state.name,
|
||||
},
|
||||
});
|
||||
|
||||
Events.hasError(response);
|
||||
@ -121,13 +127,10 @@ export default class SceneEditAccount extends React.Component {
|
||||
};
|
||||
|
||||
_handleChangePassword = async (e) => {
|
||||
if (this.state.password !== this.state.confirm) {
|
||||
Events.dispatchMessage({ message: "Passwords did not match" });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Validations.password(this.state.password)) {
|
||||
Events.dispatchMessage({ message: "Password length must be more than 8 characters" });
|
||||
Events.dispatchMessage({
|
||||
message: "Password does not meet requirements",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@ -135,7 +138,7 @@ export default class SceneEditAccount extends React.Component {
|
||||
|
||||
let response = await Actions.updateViewer({
|
||||
type: "CHANGE_PASSWORD",
|
||||
password: this.state.password,
|
||||
user: { password: this.state.password },
|
||||
});
|
||||
|
||||
if (Events.hasError(response)) {
|
||||
@ -218,7 +221,7 @@ export default class SceneEditAccount extends React.Component {
|
||||
|
||||
<div css={STYLES_HEADER}>Bio</div>
|
||||
<System.Textarea
|
||||
maxlength="2000"
|
||||
maxLength="2000"
|
||||
name="body"
|
||||
value={this.state.body}
|
||||
placeholder="A bit about yourself..."
|
||||
@ -281,7 +284,10 @@ export default class SceneEditAccount extends React.Component {
|
||||
{tab === "security" ? (
|
||||
<div>
|
||||
<div css={STYLES_HEADER}>Change password</div>
|
||||
<div>Passwords must be a minimum of eight characters.</div>
|
||||
<div>
|
||||
Passwords should be at least 8 characters long, contain a mix of upper and lowercase
|
||||
letters, and have at least 1 number and 1 symbol
|
||||
</div>
|
||||
|
||||
<System.Input
|
||||
containerStyle={{ marginTop: 24 }}
|
||||
@ -364,7 +370,7 @@ export default class SceneEditAccount extends React.Component {
|
||||
header={`Are you sure you want to delete your account @${this.state.username}?`}
|
||||
subHeader={`You will lose all your files and collections. You can’t undo this action.`}
|
||||
inputHeader={`Please type your username to confirm`}
|
||||
inputPlaceholder={`username`}
|
||||
inputPlaceholder={`Username`}
|
||||
/>
|
||||
)}
|
||||
</ScenePage>
|
||||
|
@ -57,7 +57,10 @@ export default class SceneFilesFolder extends React.Component {
|
||||
) : (
|
||||
<EmptyState>
|
||||
<FileTypeGroup />
|
||||
<div style={{ marginTop: 24 }}>Drag and drop files into Slate to upload</div>
|
||||
<div style={{ marginTop: 24 }}>
|
||||
Drag and drop files into Slate to upload, or press the plus button to save a file or
|
||||
link
|
||||
</div>
|
||||
</EmptyState>
|
||||
)}
|
||||
</ScenePage>
|
||||
|
@ -402,7 +402,7 @@ class SlatePage extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { user, objects, body, isPublic, ownerId } = this.props.data;
|
||||
const { user, name, objects, body, isPublic, ownerId } = this.props.data;
|
||||
const isOwner = this.props.viewer ? ownerId === this.props.viewer.id : false;
|
||||
|
||||
let actions = isOwner ? (
|
||||
@ -453,11 +453,11 @@ class SlatePage extends React.Component {
|
||||
{user.username}
|
||||
</span>{" "}
|
||||
</Link>
|
||||
/ {data.name}
|
||||
/ {name}
|
||||
</span>
|
||||
) : (
|
||||
<div css={Styles.HORIZONTAL_CONTAINER_CENTERED}>
|
||||
<span>{data.name}</span>
|
||||
<span>{name}</span>
|
||||
{isOwner && !isPublic && (
|
||||
<div css={STYLES_SECURITY_LOCK_WRAPPER} style={{ marginLeft: 16 }}>
|
||||
<SVG.SecurityLock height="16px" style={{ display: "block" }} />
|
||||
|
@ -27,7 +27,7 @@ const app = next({
|
||||
|
||||
const createLimiter = limit({
|
||||
windowMs: 10 * 60 * 1000, // 10 minutes
|
||||
max: 5,
|
||||
max: 10,
|
||||
message: {
|
||||
decorator: "SIGN_UP_RATE_LIMITED",
|
||||
error: true,
|
||||
@ -37,7 +37,7 @@ const createLimiter = limit({
|
||||
|
||||
const loginLimiter = limit({
|
||||
windowMs: 10 * 60 * 1000, // 10 minutes
|
||||
max: 5,
|
||||
max: 10,
|
||||
message: {
|
||||
decorator: "SIGN_IN_RATE_LIMITED",
|
||||
error: true,
|
||||
|
Loading…
Reference in New Issue
Block a user