fix: user profile not rendering in top navbar
This commit is contained in:
		@@ -1,6 +1,6 @@
 | 
				
			|||||||
overwrite: true
 | 
					overwrite: true
 | 
				
			||||||
schema:
 | 
					schema:
 | 
				
			||||||
  - '../internal/graph/schema.graphqls'
 | 
					  - '../internal/graph/schema/*.gql'
 | 
				
			||||||
documents:
 | 
					documents:
 | 
				
			||||||
  - 'src/shared/graphql/*.graphqls'
 | 
					  - 'src/shared/graphql/*.graphqls'
 | 
				
			||||||
  - 'src/shared/graphql/**/*.ts'
 | 
					  - 'src/shared/graphql/**/*.ts'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,7 +57,7 @@ const LoggedInNavbar: React.FC<GlobalTopNavbarProps> = ({
 | 
				
			|||||||
    fetch('/auth/logout', {
 | 
					    fetch('/auth/logout', {
 | 
				
			||||||
      method: 'POST',
 | 
					      method: 'POST',
 | 
				
			||||||
      credentials: 'include',
 | 
					      credentials: 'include',
 | 
				
			||||||
    }).then(async x => {
 | 
					    }).then(async (x) => {
 | 
				
			||||||
      const { status } = x;
 | 
					      const { status } = x;
 | 
				
			||||||
      if (status === 200) {
 | 
					      if (status === 200) {
 | 
				
			||||||
        cache.reset();
 | 
					        cache.reset();
 | 
				
			||||||
@@ -99,11 +99,11 @@ const LoggedInNavbar: React.FC<GlobalTopNavbarProps> = ({
 | 
				
			|||||||
      showPopup(
 | 
					      showPopup(
 | 
				
			||||||
        $target,
 | 
					        $target,
 | 
				
			||||||
        <NotificationPopup>
 | 
					        <NotificationPopup>
 | 
				
			||||||
          {data.notifications.map(notification => (
 | 
					          {data.notifications.map((notification) => (
 | 
				
			||||||
            <NotificationItem
 | 
					            <NotificationItem
 | 
				
			||||||
              title={notification.entity.name}
 | 
					              title={notification.notification.actionType}
 | 
				
			||||||
              description={`${notification.actor.name} added you as a meber to the task "${notification.entity.name}"`}
 | 
					              description={`${notification.notification.causedBy.fullname} added you as a meber to the task "${notification.notification.actionType}"`}
 | 
				
			||||||
              createdAt={notification.createdAt}
 | 
					              createdAt={notification.notification.createdAt}
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          ))}
 | 
					          ))}
 | 
				
			||||||
        </NotificationPopup>,
 | 
					        </NotificationPopup>,
 | 
				
			||||||
@@ -116,7 +116,7 @@ const LoggedInNavbar: React.FC<GlobalTopNavbarProps> = ({
 | 
				
			|||||||
  // const userIsTeamOrProjectAdmin = user.isAdmin(PermissionLevel.TEAM, PermissionObjectType.TEAM, teamID);
 | 
					  // const userIsTeamOrProjectAdmin = user.isAdmin(PermissionLevel.TEAM, PermissionObjectType.TEAM, teamID);
 | 
				
			||||||
  const userIsTeamOrProjectAdmin = true;
 | 
					  const userIsTeamOrProjectAdmin = true;
 | 
				
			||||||
  const onInvitedMemberProfile = ($targetRef: React.RefObject<HTMLElement>, email: string) => {
 | 
					  const onInvitedMemberProfile = ($targetRef: React.RefObject<HTMLElement>, email: string) => {
 | 
				
			||||||
    const member = projectInvitedMembers ? projectInvitedMembers.find(u => u.email === email) : null;
 | 
					    const member = projectInvitedMembers ? projectInvitedMembers.find((u) => u.email === email) : null;
 | 
				
			||||||
    if (member) {
 | 
					    if (member) {
 | 
				
			||||||
      showPopup(
 | 
					      showPopup(
 | 
				
			||||||
        $targetRef,
 | 
					        $targetRef,
 | 
				
			||||||
@@ -144,7 +144,7 @@ const LoggedInNavbar: React.FC<GlobalTopNavbarProps> = ({
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const onMemberProfile = ($targetRef: React.RefObject<HTMLElement>, memberID: string) => {
 | 
					  const onMemberProfile = ($targetRef: React.RefObject<HTMLElement>, memberID: string) => {
 | 
				
			||||||
    const member = projectMembers ? projectMembers.find(u => u.id === memberID) : null;
 | 
					    const member = projectMembers ? projectMembers.find((u) => u.id === memberID) : null;
 | 
				
			||||||
    const warning =
 | 
					    const warning =
 | 
				
			||||||
      'You can’t leave because you are the only admin. To make another user an admin, click their avatar, select “Change permissions…”, and select “Admin”.';
 | 
					      'You can’t leave because you are the only admin. To make another user an admin, click their avatar, select “Change permissions…”, and select “Admin”.';
 | 
				
			||||||
    if (member) {
 | 
					    if (member) {
 | 
				
			||||||
@@ -153,7 +153,7 @@ const LoggedInNavbar: React.FC<GlobalTopNavbarProps> = ({
 | 
				
			|||||||
        <MiniProfile
 | 
					        <MiniProfile
 | 
				
			||||||
          warning={member.role && member.role.code === 'owner' ? warning : null}
 | 
					          warning={member.role && member.role.code === 'owner' ? warning : null}
 | 
				
			||||||
          canChangeRole={userIsTeamOrProjectAdmin}
 | 
					          canChangeRole={userIsTeamOrProjectAdmin}
 | 
				
			||||||
          onChangeRole={roleCode => {
 | 
					          onChangeRole={(roleCode) => {
 | 
				
			||||||
            if (onChangeRole) {
 | 
					            if (onChangeRole) {
 | 
				
			||||||
              onChangeRole(member.id, roleCode);
 | 
					              onChangeRole(member.id, roleCode);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -174,6 +174,12 @@ const LoggedInNavbar: React.FC<GlobalTopNavbarProps> = ({
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (data) {
 | 
				
			||||||
 | 
					    console.log('HERE DATA');
 | 
				
			||||||
 | 
					    console.log(data.me);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    console.log('NO DATA');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  const user = data ? data.me?.user : null;
 | 
					  const user = data ? data.me?.user : null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
@@ -181,7 +187,7 @@ const LoggedInNavbar: React.FC<GlobalTopNavbarProps> = ({
 | 
				
			|||||||
      <TopNavbar
 | 
					      <TopNavbar
 | 
				
			||||||
        name={name}
 | 
					        name={name}
 | 
				
			||||||
        menuType={menuType}
 | 
					        menuType={menuType}
 | 
				
			||||||
        onOpenProjectFinder={$target => {
 | 
					        onOpenProjectFinder={($target) => {
 | 
				
			||||||
          showPopup(
 | 
					          showPopup(
 | 
				
			||||||
            $target,
 | 
					            $target,
 | 
				
			||||||
            <Popup tab={0} title={null}>
 | 
					            <Popup tab={0} title={null}>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,10 +42,6 @@ export enum ActivityType {
 | 
				
			|||||||
  TaskChecklistRemoved = 'TASK_CHECKLIST_REMOVED'
 | 
					  TaskChecklistRemoved = 'TASK_CHECKLIST_REMOVED'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export enum ActorType {
 | 
					 | 
				
			||||||
  User = 'USER'
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export type AddTaskLabelInput = {
 | 
					export type AddTaskLabelInput = {
 | 
				
			||||||
  taskID: Scalars['UUID'];
 | 
					  taskID: Scalars['UUID'];
 | 
				
			||||||
  projectLabelID: Scalars['UUID'];
 | 
					  projectLabelID: Scalars['UUID'];
 | 
				
			||||||
@@ -268,10 +264,6 @@ export type DuplicateTaskGroupPayload = {
 | 
				
			|||||||
  taskGroup: TaskGroup;
 | 
					  taskGroup: TaskGroup;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export enum EntityType {
 | 
					 | 
				
			||||||
  Task = 'TASK'
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export type FindProject = {
 | 
					export type FindProject = {
 | 
				
			||||||
  projectID: Scalars['UUID'];
 | 
					  projectID: Scalars['UUID'];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -791,25 +783,31 @@ export type NewUserAccount = {
 | 
				
			|||||||
export type Notification = {
 | 
					export type Notification = {
 | 
				
			||||||
  __typename?: 'Notification';
 | 
					  __typename?: 'Notification';
 | 
				
			||||||
  id: Scalars['ID'];
 | 
					  id: Scalars['ID'];
 | 
				
			||||||
  entity: NotificationEntity;
 | 
					 | 
				
			||||||
  actionType: ActionType;
 | 
					  actionType: ActionType;
 | 
				
			||||||
  actor: NotificationActor;
 | 
					  causedBy: NotificationCausedBy;
 | 
				
			||||||
  read: Scalars['Boolean'];
 | 
					  data: Array<NotificationData>;
 | 
				
			||||||
  createdAt: Scalars['Time'];
 | 
					  createdAt: Scalars['Time'];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type NotificationActor = {
 | 
					export type NotificationCausedBy = {
 | 
				
			||||||
  __typename?: 'NotificationActor';
 | 
					  __typename?: 'NotificationCausedBy';
 | 
				
			||||||
  id: Scalars['UUID'];
 | 
					  fullname: Scalars['String'];
 | 
				
			||||||
  type: ActorType;
 | 
					  username: Scalars['String'];
 | 
				
			||||||
  name: Scalars['String'];
 | 
					  id: Scalars['ID'];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type NotificationEntity = {
 | 
					export type NotificationData = {
 | 
				
			||||||
  __typename?: 'NotificationEntity';
 | 
					  __typename?: 'NotificationData';
 | 
				
			||||||
  id: Scalars['UUID'];
 | 
					  key: Scalars['String'];
 | 
				
			||||||
  type: EntityType;
 | 
					  value: Scalars['String'];
 | 
				
			||||||
  name: Scalars['String'];
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type Notified = {
 | 
				
			||||||
 | 
					  __typename?: 'Notified';
 | 
				
			||||||
 | 
					  id: Scalars['ID'];
 | 
				
			||||||
 | 
					  notification: Notification;
 | 
				
			||||||
 | 
					  read: Scalars['Boolean'];
 | 
				
			||||||
 | 
					  readAt?: Maybe<Scalars['Time']>;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export enum ObjectType {
 | 
					export enum ObjectType {
 | 
				
			||||||
@@ -902,7 +900,7 @@ export type Query = {
 | 
				
			|||||||
  labelColors: Array<LabelColor>;
 | 
					  labelColors: Array<LabelColor>;
 | 
				
			||||||
  me?: Maybe<MePayload>;
 | 
					  me?: Maybe<MePayload>;
 | 
				
			||||||
  myTasks: MyTasksPayload;
 | 
					  myTasks: MyTasksPayload;
 | 
				
			||||||
  notifications: Array<Notification>;
 | 
					  notifications: Array<Notified>;
 | 
				
			||||||
  organizations: Array<Organization>;
 | 
					  organizations: Array<Organization>;
 | 
				
			||||||
  projects: Array<Project>;
 | 
					  projects: Array<Project>;
 | 
				
			||||||
  searchMembers: Array<MemberSearchResult>;
 | 
					  searchMembers: Array<MemberSearchResult>;
 | 
				
			||||||
@@ -995,6 +993,11 @@ export type SortTaskGroupPayload = {
 | 
				
			|||||||
  tasks: Array<Task>;
 | 
					  tasks: Array<Task>;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type Subscription = {
 | 
				
			||||||
 | 
					  __typename?: 'Subscription';
 | 
				
			||||||
 | 
					  notificationAdded: Notified;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type Task = {
 | 
					export type Task = {
 | 
				
			||||||
  __typename?: 'Task';
 | 
					  __typename?: 'Task';
 | 
				
			||||||
  id: Scalars['ID'];
 | 
					  id: Scalars['ID'];
 | 
				
			||||||
@@ -2355,14 +2358,15 @@ export type TopNavbarQueryVariables = Exact<{ [key: string]: never; }>;
 | 
				
			|||||||
export type TopNavbarQuery = (
 | 
					export type TopNavbarQuery = (
 | 
				
			||||||
  { __typename?: 'Query' }
 | 
					  { __typename?: 'Query' }
 | 
				
			||||||
  & { notifications: Array<(
 | 
					  & { notifications: Array<(
 | 
				
			||||||
    { __typename?: 'Notification' }
 | 
					    { __typename?: 'Notified' }
 | 
				
			||||||
    & Pick<Notification, 'createdAt' | 'read' | 'id' | 'actionType'>
 | 
					    & Pick<Notified, 'id' | 'read' | 'readAt'>
 | 
				
			||||||
    & { entity: (
 | 
					    & { notification: (
 | 
				
			||||||
      { __typename?: 'NotificationEntity' }
 | 
					      { __typename?: 'Notification' }
 | 
				
			||||||
      & Pick<NotificationEntity, 'id' | 'type' | 'name'>
 | 
					      & Pick<Notification, 'id' | 'actionType' | 'createdAt'>
 | 
				
			||||||
    ), actor: (
 | 
					      & { causedBy: (
 | 
				
			||||||
      { __typename?: 'NotificationActor' }
 | 
					        { __typename?: 'NotificationCausedBy' }
 | 
				
			||||||
      & Pick<NotificationActor, 'id' | 'type' | 'name'>
 | 
					        & Pick<NotificationCausedBy, 'username' | 'fullname' | 'id'>
 | 
				
			||||||
 | 
					      ) }
 | 
				
			||||||
    ) }
 | 
					    ) }
 | 
				
			||||||
  )>, me?: Maybe<(
 | 
					  )>, me?: Maybe<(
 | 
				
			||||||
    { __typename?: 'MePayload' }
 | 
					    { __typename?: 'MePayload' }
 | 
				
			||||||
@@ -4819,20 +4823,19 @@ export type ToggleTaskLabelMutationOptions = Apollo.BaseMutationOptions<ToggleTa
 | 
				
			|||||||
export const TopNavbarDocument = gql`
 | 
					export const TopNavbarDocument = gql`
 | 
				
			||||||
    query topNavbar {
 | 
					    query topNavbar {
 | 
				
			||||||
  notifications {
 | 
					  notifications {
 | 
				
			||||||
    createdAt
 | 
					 | 
				
			||||||
    read
 | 
					 | 
				
			||||||
    id
 | 
					    id
 | 
				
			||||||
    entity {
 | 
					    read
 | 
				
			||||||
 | 
					    readAt
 | 
				
			||||||
 | 
					    notification {
 | 
				
			||||||
      id
 | 
					      id
 | 
				
			||||||
      type
 | 
					      actionType
 | 
				
			||||||
      name
 | 
					      causedBy {
 | 
				
			||||||
 | 
					        username
 | 
				
			||||||
 | 
					        fullname
 | 
				
			||||||
 | 
					        id
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      createdAt
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    actor {
 | 
					 | 
				
			||||||
      id
 | 
					 | 
				
			||||||
      type
 | 
					 | 
				
			||||||
      name
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    actionType
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  me {
 | 
					  me {
 | 
				
			||||||
    user {
 | 
					    user {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,20 +3,19 @@ import gql from 'graphql-tag';
 | 
				
			|||||||
export const TOP_NAVBAR_QUERY = gql`
 | 
					export const TOP_NAVBAR_QUERY = gql`
 | 
				
			||||||
  query topNavbar {
 | 
					  query topNavbar {
 | 
				
			||||||
    notifications {
 | 
					    notifications {
 | 
				
			||||||
      createdAt
 | 
					 | 
				
			||||||
      read
 | 
					 | 
				
			||||||
      id
 | 
					      id
 | 
				
			||||||
      entity {
 | 
					      read
 | 
				
			||||||
 | 
					      readAt
 | 
				
			||||||
 | 
					      notification {
 | 
				
			||||||
        id
 | 
					        id
 | 
				
			||||||
        type
 | 
					        actionType
 | 
				
			||||||
        name
 | 
					        causedBy {
 | 
				
			||||||
 | 
					          username
 | 
				
			||||||
 | 
					          fullname
 | 
				
			||||||
 | 
					          id
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        createdAt
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      actor {
 | 
					 | 
				
			||||||
        id
 | 
					 | 
				
			||||||
        type
 | 
					 | 
				
			||||||
        name
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      actionType
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    me {
 | 
					    me {
 | 
				
			||||||
      user {
 | 
					      user {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ import (
 | 
				
			|||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/RichardKnop/machinery/v1"
 | 
				
			||||||
	"github.com/golang-migrate/migrate/v4"
 | 
						"github.com/golang-migrate/migrate/v4"
 | 
				
			||||||
	"github.com/golang-migrate/migrate/v4/database/postgres"
 | 
						"github.com/golang-migrate/migrate/v4/database/postgres"
 | 
				
			||||||
	"github.com/golang-migrate/migrate/v4/source/httpfs"
 | 
						"github.com/golang-migrate/migrate/v4/source/httpfs"
 | 
				
			||||||
@@ -30,9 +31,13 @@ func newWebCmd() *cobra.Command {
 | 
				
			|||||||
			log.SetFormatter(Formatter)
 | 
								log.SetFormatter(Formatter)
 | 
				
			||||||
			log.SetLevel(log.InfoLevel)
 | 
								log.SetLevel(log.InfoLevel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			connection := config.GetDatabaseConnectionUri()
 | 
								appConfig, err := config.GetAppConfig()
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								connection := appConfig.Database.GetDatabaseConnectionUri()
 | 
				
			||||||
			var db *sqlx.DB
 | 
								var db *sqlx.DB
 | 
				
			||||||
			var err error
 | 
					 | 
				
			||||||
			var retryDuration time.Duration
 | 
								var retryDuration time.Duration
 | 
				
			||||||
			maxRetryNumber := 4
 | 
								maxRetryNumber := 4
 | 
				
			||||||
			for i := 0; i < maxRetryNumber; i++ {
 | 
								for i := 0; i < maxRetryNumber; i++ {
 | 
				
			||||||
@@ -61,11 +66,16 @@ func newWebCmd() *cobra.Command {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			appConfig, err := config.GetAppConfig()
 | 
								var server *machinery.Server
 | 
				
			||||||
			if err != nil {
 | 
								if appConfig.Job.Enabled {
 | 
				
			||||||
				return err
 | 
									jobConfig := appConfig.Job.GetJobConfig()
 | 
				
			||||||
 | 
									server, err = machinery.NewServer(&jobConfig)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			r, _ := route.NewRouter(db, appConfig)
 | 
					
 | 
				
			||||||
 | 
								r, _ := route.NewRouter(db, server, appConfig)
 | 
				
			||||||
			log.WithFields(log.Fields{"url": viper.GetString("server.hostname")}).Info("starting server")
 | 
								log.WithFields(log.Fields{"url": viper.GetString("server.hostname")}).Info("starting server")
 | 
				
			||||||
			return http.ListenAndServe(viper.GetString("server.hostname"), r)
 | 
								return http.ListenAndServe(viper.GetString("server.hostname"), r)
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,16 @@
 | 
				
			|||||||
package commands
 | 
					package commands
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/spf13/cobra"
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
	"github.com/spf13/viper"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/RichardKnop/machinery/v1"
 | 
						"github.com/RichardKnop/machinery/v1"
 | 
				
			||||||
	"github.com/RichardKnop/machinery/v1/config"
 | 
					 | 
				
			||||||
	queueLog "github.com/RichardKnop/machinery/v1/log"
 | 
						queueLog "github.com/RichardKnop/machinery/v1/log"
 | 
				
			||||||
	"github.com/jmoiron/sqlx"
 | 
						"github.com/jmoiron/sqlx"
 | 
				
			||||||
 | 
						"github.com/jordanknott/taskcafe/internal/config"
 | 
				
			||||||
	repo "github.com/jordanknott/taskcafe/internal/db"
 | 
						repo "github.com/jordanknott/taskcafe/internal/db"
 | 
				
			||||||
	"github.com/jordanknott/taskcafe/internal/notification"
 | 
						"github.com/jordanknott/taskcafe/internal/jobs"
 | 
				
			||||||
	log "github.com/sirupsen/logrus"
 | 
						log "github.com/sirupsen/logrus"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -28,13 +26,11 @@ func newWorkerCmd() *cobra.Command {
 | 
				
			|||||||
			log.SetFormatter(Formatter)
 | 
								log.SetFormatter(Formatter)
 | 
				
			||||||
			log.SetLevel(log.InfoLevel)
 | 
								log.SetLevel(log.InfoLevel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			connection := fmt.Sprintf("user=%s password=%s host=%s dbname=%s sslmode=disable",
 | 
								appConfig, err := config.GetAppConfig()
 | 
				
			||||||
				viper.GetString("database.user"),
 | 
								if err != nil {
 | 
				
			||||||
				viper.GetString("database.password"),
 | 
									log.Panic(err)
 | 
				
			||||||
				viper.GetString("database.host"),
 | 
								}
 | 
				
			||||||
				viper.GetString("database.name"),
 | 
								db, err := sqlx.Connect("postgres", config.GetDatabaseConfig().GetDatabaseConnectionUri())
 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
			db, err := sqlx.Connect("postgres", connection)
 | 
					 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				log.Panic(err)
 | 
									log.Panic(err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -43,25 +39,15 @@ func newWorkerCmd() *cobra.Command {
 | 
				
			|||||||
			db.SetConnMaxLifetime(5 * time.Minute)
 | 
								db.SetConnMaxLifetime(5 * time.Minute)
 | 
				
			||||||
			defer db.Close()
 | 
								defer db.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			var cnf = &config.Config{
 | 
					 | 
				
			||||||
				Broker:        viper.GetString("queue.broker"),
 | 
					 | 
				
			||||||
				DefaultQueue:  "machinery_tasks",
 | 
					 | 
				
			||||||
				ResultBackend: viper.GetString("queue.store"),
 | 
					 | 
				
			||||||
				AMQP: &config.AMQPConfig{
 | 
					 | 
				
			||||||
					Exchange:     "machinery_exchange",
 | 
					 | 
				
			||||||
					ExchangeType: "direct",
 | 
					 | 
				
			||||||
					BindingKey:   "machinery_task",
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			log.Info("starting task queue server instance")
 | 
								log.Info("starting task queue server instance")
 | 
				
			||||||
			server, err := machinery.NewServer(cnf)
 | 
								jobConfig := appConfig.Job.GetJobConfig()
 | 
				
			||||||
 | 
								server, err := machinery.NewServer(&jobConfig)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				// do something with the error
 | 
									// do something with the error
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			queueLog.Set(¬ification.MachineryLogger{})
 | 
								queueLog.Set(&jobs.MachineryLogger{})
 | 
				
			||||||
			repo := *repo.NewRepository(db)
 | 
								repo := *repo.NewRepository(db)
 | 
				
			||||||
			notification.RegisterTasks(server, repo)
 | 
								jobs.RegisterTasks(server, repo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			worker := server.NewWorker("taskcafe_worker", 10)
 | 
								worker := server.NewWorker("taskcafe_worker", 10)
 | 
				
			||||||
			log.Info("starting task queue worker")
 | 
								log.Info("starting task queue worker")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mConfig "github.com/RichardKnop/machinery/v1/config"
 | 
				
			||||||
	"github.com/google/uuid"
 | 
						"github.com/google/uuid"
 | 
				
			||||||
	log "github.com/sirupsen/logrus"
 | 
						log "github.com/sirupsen/logrus"
 | 
				
			||||||
	"github.com/spf13/viper"
 | 
						"github.com/spf13/viper"
 | 
				
			||||||
@@ -22,8 +23,10 @@ const (
 | 
				
			|||||||
	SecurityTokenExpiration = "security.token_expiration"
 | 
						SecurityTokenExpiration = "security.token_expiration"
 | 
				
			||||||
	SecuritySecret          = "security.secret"
 | 
						SecuritySecret          = "security.secret"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QueueBroker = "queue.broker"
 | 
						JobEnabled   = "job.enabled"
 | 
				
			||||||
	QueueStore  = "queue.store"
 | 
						JobBroker    = "job.broker"
 | 
				
			||||||
 | 
						JobStore     = "job.store"
 | 
				
			||||||
 | 
						JobQueueName = "job.queue_name"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SmtpFrom       = "smtp.from"
 | 
						SmtpFrom       = "smtp.from"
 | 
				
			||||||
	SmtpHost       = "smtp.host"
 | 
						SmtpHost       = "smtp.host"
 | 
				
			||||||
@@ -33,7 +36,7 @@ const (
 | 
				
			|||||||
	SmtpSkipVerify = "false"
 | 
						SmtpSkipVerify = "false"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var defaults = map[string]string{
 | 
					var defaults = map[string]interface{}{
 | 
				
			||||||
	ServerHostname:          "0.0.0.0:3333",
 | 
						ServerHostname:          "0.0.0.0:3333",
 | 
				
			||||||
	DatabaseHost:            "127.0.0.1",
 | 
						DatabaseHost:            "127.0.0.1",
 | 
				
			||||||
	DatabaseName:            "taskcafe",
 | 
						DatabaseName:            "taskcafe",
 | 
				
			||||||
@@ -43,14 +46,16 @@ var defaults = map[string]string{
 | 
				
			|||||||
	DatabaseSslMode:         "disable",
 | 
						DatabaseSslMode:         "disable",
 | 
				
			||||||
	SecurityTokenExpiration: "15m",
 | 
						SecurityTokenExpiration: "15m",
 | 
				
			||||||
	SecuritySecret:          "",
 | 
						SecuritySecret:          "",
 | 
				
			||||||
	QueueBroker:             "amqp://guest:guest@localhost:5672/",
 | 
						JobEnabled:              false,
 | 
				
			||||||
	QueueStore:              "memcache://localhost:11211",
 | 
						JobBroker:               "amqp://guest:guest@localhost:5672/",
 | 
				
			||||||
 | 
						JobStore:                "memcache://localhost:11211",
 | 
				
			||||||
 | 
						JobQueueName:            "taskcafe_tasks",
 | 
				
			||||||
	SmtpFrom:                "no-reply@example.com",
 | 
						SmtpFrom:                "no-reply@example.com",
 | 
				
			||||||
	SmtpHost:                "localhost",
 | 
						SmtpHost:                "localhost",
 | 
				
			||||||
	SmtpPort:                "587",
 | 
						SmtpPort:                "587",
 | 
				
			||||||
	SmtpUsername:            "",
 | 
						SmtpUsername:            "",
 | 
				
			||||||
	SmtpPassword:            "",
 | 
						SmtpPassword:            "",
 | 
				
			||||||
	SmtpSkipVerify:          "false",
 | 
						SmtpSkipVerify:          false,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func InitDefaults() {
 | 
					func InitDefaults() {
 | 
				
			||||||
@@ -59,21 +64,40 @@ func InitDefaults() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GetDatabaseConnectionUri() string {
 | 
					 | 
				
			||||||
	connection := fmt.Sprintf("user=%s password=%s host=%s dbname=%s port=%s sslmode=%s",
 | 
					 | 
				
			||||||
		viper.GetString(DatabaseUser),
 | 
					 | 
				
			||||||
		viper.GetString(DatabasePassword),
 | 
					 | 
				
			||||||
		viper.GetString(DatabaseHost),
 | 
					 | 
				
			||||||
		viper.GetString(DatabaseName),
 | 
					 | 
				
			||||||
		viper.GetString(DatabasePort),
 | 
					 | 
				
			||||||
		viper.GetString(DatabaseSslMode),
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	return connection
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type AppConfig struct {
 | 
					type AppConfig struct {
 | 
				
			||||||
	Email    EmailConfig
 | 
						Email    EmailConfig
 | 
				
			||||||
	Security SecurityConfig
 | 
						Security SecurityConfig
 | 
				
			||||||
 | 
						Database DatabaseConfig
 | 
				
			||||||
 | 
						Job      JobConfig
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type JobConfig struct {
 | 
				
			||||||
 | 
						Enabled   bool
 | 
				
			||||||
 | 
						Broker    string
 | 
				
			||||||
 | 
						QueueName string
 | 
				
			||||||
 | 
						Store     string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GetJobConfig() JobConfig {
 | 
				
			||||||
 | 
						return JobConfig{
 | 
				
			||||||
 | 
							Enabled:   viper.GetBool(JobEnabled),
 | 
				
			||||||
 | 
							Broker:    viper.GetString(JobBroker),
 | 
				
			||||||
 | 
							QueueName: viper.GetString(JobQueueName),
 | 
				
			||||||
 | 
							Store:     viper.GetString(JobStore),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (cfg *JobConfig) GetJobConfig() mConfig.Config {
 | 
				
			||||||
 | 
						return mConfig.Config{
 | 
				
			||||||
 | 
							Broker:        cfg.Broker,
 | 
				
			||||||
 | 
							DefaultQueue:  cfg.QueueName,
 | 
				
			||||||
 | 
							ResultBackend: cfg.Store,
 | 
				
			||||||
 | 
							AMQP: &mConfig.AMQPConfig{
 | 
				
			||||||
 | 
								Exchange:     "machinery_exchange",
 | 
				
			||||||
 | 
								ExchangeType: "direct",
 | 
				
			||||||
 | 
								BindingKey:   "machinery_task",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type EmailConfig struct {
 | 
					type EmailConfig struct {
 | 
				
			||||||
@@ -86,6 +110,27 @@ type EmailConfig struct {
 | 
				
			|||||||
	InsecureSkipVerify bool
 | 
						InsecureSkipVerify bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type DatabaseConfig struct {
 | 
				
			||||||
 | 
						Host     string
 | 
				
			||||||
 | 
						Port     string
 | 
				
			||||||
 | 
						Name     string
 | 
				
			||||||
 | 
						Username string
 | 
				
			||||||
 | 
						Password string
 | 
				
			||||||
 | 
						SslMode  string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (cfg DatabaseConfig) GetDatabaseConnectionUri() string {
 | 
				
			||||||
 | 
						connection := fmt.Sprintf("user=%s password=%s host=%s dbname=%s port=%s sslmode=%s",
 | 
				
			||||||
 | 
							cfg.Username,
 | 
				
			||||||
 | 
							cfg.Password,
 | 
				
			||||||
 | 
							cfg.Host,
 | 
				
			||||||
 | 
							cfg.Name,
 | 
				
			||||||
 | 
							cfg.Port,
 | 
				
			||||||
 | 
							cfg.SslMode,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						return connection
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type SecurityConfig struct {
 | 
					type SecurityConfig struct {
 | 
				
			||||||
	AccessTokenExpiration time.Duration
 | 
						AccessTokenExpiration time.Duration
 | 
				
			||||||
	Secret                []byte
 | 
						Secret                []byte
 | 
				
			||||||
@@ -101,10 +146,14 @@ func GetAppConfig() (AppConfig, error) {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return AppConfig{}, err
 | 
							return AppConfig{}, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						jobCfg := GetJobConfig()
 | 
				
			||||||
 | 
						databaseCfg := GetDatabaseConfig()
 | 
				
			||||||
	emailCfg := GetEmailConfig()
 | 
						emailCfg := GetEmailConfig()
 | 
				
			||||||
	return AppConfig{
 | 
						return AppConfig{
 | 
				
			||||||
		Email:    emailCfg,
 | 
							Email:    emailCfg,
 | 
				
			||||||
		Security: securityCfg,
 | 
							Security: securityCfg,
 | 
				
			||||||
 | 
							Database: databaseCfg,
 | 
				
			||||||
 | 
							Job:      jobCfg,
 | 
				
			||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -119,11 +168,22 @@ func GetSecurityConfig(accessTokenExp string, secret []byte) (SecurityConfig, er
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func GetEmailConfig() EmailConfig {
 | 
					func GetEmailConfig() EmailConfig {
 | 
				
			||||||
	return EmailConfig{
 | 
						return EmailConfig{
 | 
				
			||||||
		From:               viper.GetString("smtp.from"),
 | 
							From:               viper.GetString(SmtpFrom),
 | 
				
			||||||
		Host:               viper.GetString("smtp.host"),
 | 
							Host:               viper.GetString(SmtpHost),
 | 
				
			||||||
		Port:               viper.GetInt("smtp.port"),
 | 
							Port:               viper.GetInt(SmtpPort),
 | 
				
			||||||
		Username:           viper.GetString("smtp.username"),
 | 
							Username:           viper.GetString(SmtpUsername),
 | 
				
			||||||
		Password:           viper.GetString("smtp.password"),
 | 
							Password:           viper.GetString(SmtpPassword),
 | 
				
			||||||
		InsecureSkipVerify: viper.GetBool("smtp.skip_verify"),
 | 
							InsecureSkipVerify: viper.GetBool(SmtpSkipVerify),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GetDatabaseConfig() DatabaseConfig {
 | 
				
			||||||
 | 
						return DatabaseConfig{
 | 
				
			||||||
 | 
							Username: viper.GetString(DatabaseUser),
 | 
				
			||||||
 | 
							Password: viper.GetString(DatabasePassword),
 | 
				
			||||||
 | 
							Port:     viper.GetString(DatabasePort),
 | 
				
			||||||
 | 
							SslMode:  viper.GetString(DatabaseSslMode),
 | 
				
			||||||
 | 
							Name:     viper.GetString(DatabaseName),
 | 
				
			||||||
 | 
							Host:     viper.GetString(DatabaseHost),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2047,7 +2047,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		return e.complexity.Notified.Read(childComplexity), true
 | 
							return e.complexity.Notified.Read(childComplexity), true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case "Notified.read_at":
 | 
						case "Notified.readAt":
 | 
				
			||||||
		if e.complexity.Notified.ReadAt == nil {
 | 
							if e.complexity.Notified.ReadAt == nil {
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -3185,7 +3185,7 @@ type Notified {
 | 
				
			|||||||
  id: ID!
 | 
					  id: ID!
 | 
				
			||||||
  notification: Notification!
 | 
					  notification: Notification!
 | 
				
			||||||
  read: Boolean!
 | 
					  read: Boolean!
 | 
				
			||||||
  read_at: Time
 | 
					  readAt: Time
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`, BuiltIn: false},
 | 
					`, BuiltIn: false},
 | 
				
			||||||
@@ -12388,7 +12388,7 @@ func (ec *executionContext) _Notified_read(ctx context.Context, field graphql.Co
 | 
				
			|||||||
	return ec.marshalNBoolean2bool(ctx, field.Selections, res)
 | 
						return ec.marshalNBoolean2bool(ctx, field.Selections, res)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ec *executionContext) _Notified_read_at(ctx context.Context, field graphql.CollectedField, obj *Notified) (ret graphql.Marshaler) {
 | 
					func (ec *executionContext) _Notified_readAt(ctx context.Context, field graphql.CollectedField, obj *Notified) (ret graphql.Marshaler) {
 | 
				
			||||||
	defer func() {
 | 
						defer func() {
 | 
				
			||||||
		if r := recover(); r != nil {
 | 
							if r := recover(); r != nil {
 | 
				
			||||||
			ec.Error(ctx, ec.Recover(ctx, r))
 | 
								ec.Error(ctx, ec.Recover(ctx, r))
 | 
				
			||||||
@@ -21877,8 +21877,8 @@ func (ec *executionContext) _Notified(ctx context.Context, sel ast.SelectionSet,
 | 
				
			|||||||
			if out.Values[i] == graphql.Null {
 | 
								if out.Values[i] == graphql.Null {
 | 
				
			||||||
				invalids++
 | 
									invalids++
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		case "read_at":
 | 
							case "readAt":
 | 
				
			||||||
			out.Values[i] = ec._Notified_read_at(ctx, field, obj)
 | 
								out.Values[i] = ec._Notified_readAt(ctx, field, obj)
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			panic("unknown field " + strconv.Quote(field.Name))
 | 
								panic("unknown field " + strconv.Quote(field.Name))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -371,7 +371,7 @@ type Notified struct {
 | 
				
			|||||||
	ID           uuid.UUID        `json:"id"`
 | 
						ID           uuid.UUID        `json:"id"`
 | 
				
			||||||
	Notification *db.Notification `json:"notification"`
 | 
						Notification *db.Notification `json:"notification"`
 | 
				
			||||||
	Read         bool             `json:"read"`
 | 
						Read         bool             `json:"read"`
 | 
				
			||||||
	ReadAt       *time.Time       `json:"read_at"`
 | 
						ReadAt       *time.Time       `json:"readAt"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type OwnedList struct {
 | 
					type OwnedList struct {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ import (
 | 
				
			|||||||
	"github.com/google/uuid"
 | 
						"github.com/google/uuid"
 | 
				
			||||||
	"github.com/jordanknott/taskcafe/internal/db"
 | 
						"github.com/jordanknott/taskcafe/internal/db"
 | 
				
			||||||
	"github.com/jordanknott/taskcafe/internal/logger"
 | 
						"github.com/jordanknott/taskcafe/internal/logger"
 | 
				
			||||||
 | 
						log "github.com/sirupsen/logrus"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *notificationResolver) ID(ctx context.Context, obj *db.Notification) (uuid.UUID, error) {
 | 
					func (r *notificationResolver) ID(ctx context.Context, obj *db.Notification) (uuid.UUID, error) {
 | 
				
			||||||
@@ -23,7 +24,23 @@ func (r *notificationResolver) ActionType(ctx context.Context, obj *db.Notificat
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *notificationResolver) CausedBy(ctx context.Context, obj *db.Notification) (*NotificationCausedBy, error) {
 | 
					func (r *notificationResolver) CausedBy(ctx context.Context, obj *db.Notification) (*NotificationCausedBy, error) {
 | 
				
			||||||
	panic(fmt.Errorf("not implemented"))
 | 
						user, err := r.Repository.GetUserAccountByID(ctx, obj.CausedBy)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if err == sql.ErrNoRows {
 | 
				
			||||||
 | 
								return &NotificationCausedBy{
 | 
				
			||||||
 | 
									Fullname: "Unknown user",
 | 
				
			||||||
 | 
									Username: "unknown",
 | 
				
			||||||
 | 
									ID:       obj.CausedBy,
 | 
				
			||||||
 | 
								}, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							log.WithError(err).Error("error while resolving Notification.CausedBy")
 | 
				
			||||||
 | 
							return &NotificationCausedBy{}, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return &NotificationCausedBy{
 | 
				
			||||||
 | 
							Fullname: user.FullName,
 | 
				
			||||||
 | 
							Username: user.Username,
 | 
				
			||||||
 | 
							ID:       obj.CausedBy,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *notificationResolver) Data(ctx context.Context, obj *db.Notification) ([]NotificationData, error) {
 | 
					func (r *notificationResolver) Data(ctx context.Context, obj *db.Notification) ([]NotificationData, error) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,6 @@ type Notified {
 | 
				
			|||||||
  id: ID!
 | 
					  id: ID!
 | 
				
			||||||
  notification: Notification!
 | 
					  notification: Notification!
 | 
				
			||||||
  read: Boolean!
 | 
					  read: Boolean!
 | 
				
			||||||
  read_at: Time
 | 
					  readAt: Time
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,5 +33,5 @@ type Notified {
 | 
				
			|||||||
  id: ID!
 | 
					  id: ID!
 | 
				
			||||||
  notification: Notification!
 | 
					  notification: Notification!
 | 
				
			||||||
  read: Boolean!
 | 
					  read: Boolean!
 | 
				
			||||||
  read_at: Time
 | 
					  readAt: Time
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										33
									
								
								internal/jobs/jobs.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								internal/jobs/jobs.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					package jobs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/RichardKnop/machinery/v1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/google/uuid"
 | 
				
			||||||
 | 
						"github.com/jordanknott/taskcafe/internal/config"
 | 
				
			||||||
 | 
						"github.com/jordanknott/taskcafe/internal/db"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func RegisterTasks(server *machinery.Server, repo db.Repository) {
 | 
				
			||||||
 | 
						tasks := JobTasks{repo}
 | 
				
			||||||
 | 
						server.RegisterTasks(map[string]interface{}{
 | 
				
			||||||
 | 
							"taskMemberWasAdded": tasks.TaskMemberWasAdded,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type JobTasks struct {
 | 
				
			||||||
 | 
						Repository db.Repository
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (t *JobTasks) TaskMemberWasAdded(taskID, notifierID, notifiedID string) (bool, error) {
 | 
				
			||||||
 | 
						return true, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type JobQueue struct {
 | 
				
			||||||
 | 
						AppConfig config.AppConfig
 | 
				
			||||||
 | 
						Server    *machinery.Server
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (q *JobQueue) TaskMemberWasAdded(taskID, notifier, notified uuid.UUID) error {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package notification
 | 
					package jobs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	log "github.com/sirupsen/logrus"
 | 
						log "github.com/sirupsen/logrus"
 | 
				
			||||||
@@ -1,31 +0,0 @@
 | 
				
			|||||||
package notification
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"github.com/RichardKnop/machinery/v1"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/google/uuid"
 | 
					 | 
				
			||||||
	"github.com/jordanknott/taskcafe/internal/db"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func RegisterTasks(server *machinery.Server, repo db.Repository) {
 | 
					 | 
				
			||||||
	tasks := NotificationTasks{repo}
 | 
					 | 
				
			||||||
	server.RegisterTasks(map[string]interface{}{
 | 
					 | 
				
			||||||
		"taskMemberWasAdded": tasks.TaskMemberWasAdded,
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type NotificationTasks struct {
 | 
					 | 
				
			||||||
	Repository db.Repository
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (m *NotificationTasks) TaskMemberWasAdded(taskID, notifierID, notifiedID string) (bool, error) {
 | 
					 | 
				
			||||||
	return true, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type NotificationQueue struct {
 | 
					 | 
				
			||||||
	Server *machinery.Server
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (n *NotificationQueue) TaskMemberWasAdded(taskID, notifier, notified uuid.UUID) error {
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -4,6 +4,7 @@ import (
 | 
				
			|||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/RichardKnop/machinery/v1"
 | 
				
			||||||
	"github.com/go-chi/chi"
 | 
						"github.com/go-chi/chi"
 | 
				
			||||||
	"github.com/go-chi/chi/middleware"
 | 
						"github.com/go-chi/chi/middleware"
 | 
				
			||||||
	"github.com/go-chi/cors"
 | 
						"github.com/go-chi/cors"
 | 
				
			||||||
@@ -66,7 +67,7 @@ type TaskcafeHandler struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewRouter creates a new router for chi
 | 
					// NewRouter creates a new router for chi
 | 
				
			||||||
func NewRouter(dbConnection *sqlx.DB, appConfig config.AppConfig) (chi.Router, error) {
 | 
					func NewRouter(dbConnection *sqlx.DB, job *machinery.Server, appConfig config.AppConfig) (chi.Router, error) {
 | 
				
			||||||
	formatter := new(log.TextFormatter)
 | 
						formatter := new(log.TextFormatter)
 | 
				
			||||||
	formatter.TimestampFormat = "02-01-2006 15:04:05"
 | 
						formatter.TimestampFormat = "02-01-2006 15:04:05"
 | 
				
			||||||
	formatter.FullTimestamp = true
 | 
						formatter.FullTimestamp = true
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										36
									
								
								migrations/0067_add-user_account_settings.up.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								migrations/0067_add-user_account_settings.up.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					CREATE TABLE account_setting_data_type (
 | 
				
			||||||
 | 
					  data_type_id text PRIMARY KEY
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					INSERT INTO account_setting_data_type VALUES ('string');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CREATE TABLE account_setting (
 | 
				
			||||||
 | 
					  account_setting_id text PRIMARY KEY,
 | 
				
			||||||
 | 
					  constrained boolean NOT NULL,
 | 
				
			||||||
 | 
					  data_type text NOT NULL REFERENCES account_setting_data_type(data_type_id) ON DELETE CASCADE,
 | 
				
			||||||
 | 
					  constrained_default_value text
 | 
				
			||||||
 | 
					    REFERENCES account_setting_allowed_values(allowed_value_id) ON DELETE CASCADE,
 | 
				
			||||||
 | 
					  unconstrained_default_value text,
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					INSERT INTO account_setting VALUES ('email_notification_frequency', true, 'string');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CREATE TABLE account_setting_allowed_values (
 | 
				
			||||||
 | 
					  allowed_value_id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
 | 
				
			||||||
 | 
					  setting_id int NOT NULL REFERENCES account_setting(account_setting_id) ON DELETE CASCADE,
 | 
				
			||||||
 | 
					  item_value text NOT NULL
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					INSERT INTO account_setting_allowed_values (setting_id, item_value) VALUES (0, 'never');
 | 
				
			||||||
 | 
					INSERT INTO account_setting_allowed_values (setting_id, item_value) VALUES (0, 'hourly');
 | 
				
			||||||
 | 
					INSERT INTO account_setting_allowed_values (setting_id, item_value) VALUES (0, 'instant');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CREATE TABLE account_setting (
 | 
				
			||||||
 | 
					  account_setting_id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
 | 
				
			||||||
 | 
					  user_id uuid NOT NULL REFERENCES user_account(user_id) ON DELETE CASCADE,
 | 
				
			||||||
 | 
					  setting_id  int NOT NULL REFERENCES account_setting(account_setting_id) ON DELETE CASCADE,
 | 
				
			||||||
 | 
					  created_at timestamptz NOT NULL,
 | 
				
			||||||
 | 
					  updated_at timestamptz NOT NULL,
 | 
				
			||||||
 | 
					  allowed_value_id uuid REFERENCES account_setting_allowed_values(allowed_value_id) ON DELETE CASCADE,
 | 
				
			||||||
 | 
					  unconstrained_value text
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
		Reference in New Issue
	
	Block a user