postflow

package module
v0.0.0-...-bcea96b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 17, 2025 License: Apache-2.0 Imports: 8 Imported by: 0

README

Postflow

License Go Report Card GoDoc

Postflow is a flexible and extensible Go package for managing user posts and social media feeds. It provides a complete solution for creating, retrieving, updating, and deleting posts, as well as handling user interactions like reactions, comments, and shares.

Features

  • 📝 Complete post management (CRUD operations)
  • 🔄 Feed generation and retrieval
  • 🔍 Advanced post filtering and sorting
  • 👍 Reaction management (like, love, haha, wow, sad, angry)
  • 🏷️ Tag-based post organization
  • 🖼️ Media attachment support (images, videos, audio, files, links)
  • 🔒 Visibility control (public, private, friends)
  • 📊 Trend detection and trending post retrieval
  • 💾 Multiple storage options (in-memory and GORM-based database backends)

Installation

go get github.com/weedbox/postflow

Quick Start

package main

import (
	"context"
	"fmt"
	"github.com/google/uuid"
	"github.com/weedbox/postflow"
	"time"
)

func main() {
	// Create an in-memory store
	store := postflow.NewInMemoryPostStore()
	
	// Create a post manager
	manager := postflow.NewPostManager(store)
	
	// Create a new post
	post := &postflow.Post{
		UserID:     "user123",
		Content:    "Hello, Postflow!",
		Tags:       []string{"hello", "example"},
		Visibility: "public",
		CreatedAt:  time.Now(),
		UpdatedAt:  time.Now(),
	}
	
	ctx := context.Background()
	
	// Save the post
	postID, err := manager.CreatePost(ctx, post)
	if err != nil {
		fmt.Printf("Error creating post: %v\n", err)
		return
	}
	
	fmt.Printf("Created post with ID: %s\n", postID)
	
	// Add a reaction to the post
	err = manager.AddReaction(ctx, postID, "user456", postflow.ReactionLike)
	if err != nil {
		fmt.Printf("Error adding reaction: %v\n", err)
		return
	}
	
	// Get the post with reaction
	retrievedPost, err := manager.GetPost(ctx, postID)
	if err != nil {
		fmt.Printf("Error retrieving post: %v\n", err)
		return
	}
	
	fmt.Printf("Post content: %s\n", retrievedPost.Content)
	fmt.Printf("Likes: %d\n", retrievedPost.Reactions[postflow.ReactionLike])
}

Storage Options

In-Memory Storage

For development, testing, or simple applications, you can use the InMemoryPostStore:

store := postflow.NewInMemoryPostStore()
manager := postflow.NewPostManager(store)
Database Storage with GORM

For production applications, you can use the GORM-based store, which supports various database backends:

import (
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

// Connect to database
db, err := gorm.Open(postgres.Open("host=localhost user=postgres password=postgres dbname=postflow port=5432 sslmode=disable"), &gorm.Config{})
if err != nil {
	panic("failed to connect to database")
}

// Create a GORM store
store, err := postflow.NewGormPostStore(db)
if err != nil {
	panic("failed to create store")
}

manager := postflow.NewPostManager(store)

Post Filtering

The package provides a flexible filtering system for retrieving posts:

// Get posts by a specific user
posts, err := manager.ListPosts(ctx, &postflow.PostFilter{
	UserID: "user123",
})

// Get posts with specific tags
posts, err := manager.ListPosts(ctx, &postflow.PostFilter{
	Tags: []string{"golang", "programming"},
})

// Get posts within a time range
posts, err := manager.ListPosts(ctx, &postflow.PostFilter{
	TimeRange: &postflow.TimeRange{
		Start: time.Now().Add(-24 * time.Hour), // Last 24 hours
		End:   time.Now(),
	},
})

// Get posts with pagination and sorting
posts, err := manager.ListPosts(ctx, &postflow.PostFilter{
	Limit:     10,
	Offset:    0,
	SortBy:    "created_at",
	SortOrder: "desc",
})

Reaction Types

The package supports several reaction types:

postflow.ReactionLike  // 👍
postflow.ReactionLove  // ❤️
postflow.ReactionHaha  // 😄
postflow.ReactionWow   // 😮
postflow.ReactionSad   // 😢
postflow.ReactionAngry // 😠

Media Support

Posts can include various types of media:

post := &postflow.Post{
	UserID:  "user123",
	Content: "Check out this photo!",
	Media: []postflow.Media{
		{
			ID:           uuid.New().String(),
			Type:         postflow.MediaTypeImage,
			URL:          "https://example.com/image.jpg",
			ThumbnailURL: "https://example.com/thumbnail.jpg",
			Description:  "Beautiful sunset",
			Width:        1920,
			Height:       1080,
			FileSize:     1024 * 1024, // 1MB
			FileName:     "sunset.jpg",
			MimeType:     "image/jpeg",
			CreatedAt:    time.Now(),
		},
	},
	Visibility: "public",
}

Feed Generation

Get a user's feed or trending posts:

// Get a user's feed
feed, err := manager.GetUserFeed(ctx, "user123", 20, 0)

// Get trending posts
trending, err := manager.GetTrendingPosts(ctx, 10)

Error Handling

The package defines several error types that you should handle in your application:

if err == postflow.ErrPostNotFound {
	// Handle post not found
}

if err == postflow.ErrPermissionDenied {
	// Handle permission denied
}

if err == postflow.ErrInvalidReaction {
	// Handle invalid reaction
}

Testing

To run the tests:

go test -v ./...

License

This project is licensed under the APL License - see the LICENSE file for details.

Documentation

Overview

Package postflow provides functionality for managing user posts and feeds.

Package postflow provides functionality for managing user posts and feeds.

The package implements a post management system that supports creating, retrieving, updating and deleting posts, as well as managing user feeds and interactions.

Package postflow provides functionality for managing user posts and feeds.

Package postflow provides functionality for managing user posts and feeds.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrPostNotFound is returned when a post is not found
	ErrPostNotFound = errors.New("post not found")

	// ErrPermissionDenied is returned when a user doesn't have permission to modify a post
	ErrPermissionDenied = errors.New("permission denied")

	// ErrInvalidReaction is returned when an invalid reaction is provided
	ErrInvalidReaction = errors.New("invalid reaction")
)

Functions

This section is empty.

Types

type GormPostStore

type GormPostStore struct {
	// contains filtered or unexported fields
}

GormPostStore implements PostStore interface with GORM as the underlying storage

func NewGormPostStore

func NewGormPostStore(db *gorm.DB) (*GormPostStore, error)

NewGormPostStore creates a new instance of GormPostStore

func (*GormPostStore) DeletePost

func (s *GormPostStore) DeletePost(ctx context.Context, postID string, userID string) error

DeletePost removes a post from the store

func (*GormPostStore) DeleteReaction

func (s *GormPostStore) DeleteReaction(ctx context.Context, postID string, userID string, reactionType ReactionType) error

DeleteReaction removes a reaction from a post

func (*GormPostStore) GetPost

func (s *GormPostStore) GetPost(ctx context.Context, postID string) (*Post, error)

GetPost retrieves a post by its ID

func (*GormPostStore) GetReactedUsers

func (s *GormPostStore) GetReactedUsers(ctx context.Context, postID string, reactionType *ReactionType, limit, offset int) ([]string, error)

GetReactedUsers returns users who reacted to a specific post

func (*GormPostStore) GetReactionCounts

func (s *GormPostStore) GetReactionCounts(ctx context.Context, postID string) (map[ReactionType]int, error)

GetReactionCounts returns the count of each reaction type for a post

func (*GormPostStore) GetTrendingPosts

func (s *GormPostStore) GetTrendingPosts(ctx context.Context, limit int) ([]*Post, error)

GetTrendingPosts retrieves currently trending posts

func (*GormPostStore) GetUserFeed

func (s *GormPostStore) GetUserFeed(ctx context.Context, userID string, limit, offset int) ([]*Post, error)

GetUserFeed retrieves posts for a user's feed

func (*GormPostStore) GetUserReaction

func (s *GormPostStore) GetUserReaction(ctx context.Context, postID string, userID string) (*ReactionType, error)

GetUserReaction gets the current reaction of a user for a post

func (*GormPostStore) ListPosts

func (s *GormPostStore) ListPosts(ctx context.Context, filter *PostFilter) ([]*Post, error)

ListPosts retrieves posts based on filter criteria

func (*GormPostStore) SavePost

func (s *GormPostStore) SavePost(ctx context.Context, post *Post) error

SavePost saves a new post or updates an existing post

func (*GormPostStore) SaveReaction

func (s *GormPostStore) SaveReaction(ctx context.Context, postID string, userID string, reactionType ReactionType) error

SaveReaction saves a reaction to a post

type InMemoryPostStore

type InMemoryPostStore struct {
	// contains filtered or unexported fields
}

InMemoryPostStore implements PostStore interface with in-memory storage

func NewInMemoryPostStore

func NewInMemoryPostStore() *InMemoryPostStore

NewInMemoryPostStore creates a new instance of InMemoryPostStore

func (*InMemoryPostStore) DeletePost

func (s *InMemoryPostStore) DeletePost(ctx context.Context, postID string, userID string) error

DeletePost removes a post from the store

func (*InMemoryPostStore) DeleteReaction

func (s *InMemoryPostStore) DeleteReaction(ctx context.Context, postID string, userID string, reactionType ReactionType) error

DeleteReaction removes a reaction from a post

func (*InMemoryPostStore) GetPost

func (s *InMemoryPostStore) GetPost(ctx context.Context, postID string) (*Post, error)

GetPost retrieves a post by its ID

func (*InMemoryPostStore) GetReactedUsers

func (s *InMemoryPostStore) GetReactedUsers(ctx context.Context, postID string, reactionType *ReactionType, limit, offset int) ([]string, error)

GetReactedUsers returns users who reacted to a specific post

func (*InMemoryPostStore) GetReactionCounts

func (s *InMemoryPostStore) GetReactionCounts(ctx context.Context, postID string) (map[ReactionType]int, error)

GetReactionCounts returns the count of each reaction type for a post

func (*InMemoryPostStore) GetTrendingPosts

func (s *InMemoryPostStore) GetTrendingPosts(ctx context.Context, limit int) ([]*Post, error)

GetTrendingPosts retrieves currently trending posts This simple implementation returns posts with most reactions and comments

func (*InMemoryPostStore) GetUserFeed

func (s *InMemoryPostStore) GetUserFeed(ctx context.Context, userID string, limit, offset int) ([]*Post, error)

GetUserFeed retrieves posts for a user's feed In a real implementation, this would consider followed users, algorithms, etc. This simple version just returns recent public posts

func (*InMemoryPostStore) GetUserReaction

func (s *InMemoryPostStore) GetUserReaction(ctx context.Context, postID string, userID string) (*ReactionType, error)

GetUserReaction gets the current reaction of a user for a post

func (*InMemoryPostStore) ListPosts

func (s *InMemoryPostStore) ListPosts(ctx context.Context, filter *PostFilter) ([]*Post, error)

ListPosts retrieves posts based on filter criteria

func (*InMemoryPostStore) SavePost

func (s *InMemoryPostStore) SavePost(ctx context.Context, post *Post) error

SavePost saves a post to the in-memory store

func (*InMemoryPostStore) SaveReaction

func (s *InMemoryPostStore) SaveReaction(ctx context.Context, postID string, userID string, reactionType ReactionType) error

SaveReaction saves a reaction to a post

type Media

type Media struct {
	ID           string    `json:"id"`
	Type         MediaType `json:"type"`
	URL          string    `json:"url"`
	ThumbnailURL string    `json:"thumbnail_url,omitempty"`
	Description  string    `json:"description,omitempty"`
	Width        int       `json:"width,omitempty"`
	Height       int       `json:"height,omitempty"`
	Duration     int       `json:"duration,omitempty"`  // Duration in seconds for video/audio
	FileSize     int64     `json:"file_size,omitempty"` // Size in bytes
	FileName     string    `json:"file_name,omitempty"`
	MimeType     string    `json:"mime_type,omitempty"`
	CreatedAt    time.Time `json:"created_at"`
}

Media represents a media item attached to a post

type MediaModel

type MediaModel struct {
	ID           string `gorm:"primaryKey"`
	PostID       string `gorm:"index"`
	Type         uint8
	URL          string
	ThumbnailURL string
	Description  string
	Width        int
	Height       int
	Duration     int
	FileSize     int64
	FileName     string
	MimeType     string
	CreatedAt    time.Time
}

MediaModel is the GORM model for storing media items

type MediaType

type MediaType uint8

MediaType represents the type of media attached to a post

const (
	MediaTypeImage MediaType = 1
	MediaTypeVideo MediaType = 2
	MediaTypeAudio MediaType = 3
	MediaTypeFile  MediaType = 4
	MediaTypeLink  MediaType = 5
)

type Post

type Post struct {
	ID         string               `json:"id"`
	UserID     string               `json:"user_id"`
	Content    string               `json:"content"`
	Media      []Media              `json:"media,omitempty"`
	Tags       []string             `json:"tags,omitempty"`
	CreatedAt  time.Time            `json:"created_at"`
	UpdatedAt  time.Time            `json:"updated_at"`
	Reactions  map[ReactionType]int `json:"reactions"`
	Comments   int                  `json:"comments"`
	Shares     int                  `json:"shares"`
	Visibility string               `json:"visibility"` // public, private, friends
}

Post represents a user post in the system.

type PostFilter

type PostFilter struct {
	UserID     string
	Tags       []string
	TimeRange  *TimeRange
	Visibility string
	Limit      int
	Offset     int
	SortBy     string
	SortOrder  string
}

PostFilter represents filtering options for retrieving posts.

type PostManager

type PostManager interface {
	// CreatePost creates a new post in the system.
	CreatePost(ctx context.Context, post *Post) (string, error)

	// GetPost retrieves a post by its ID.
	GetPost(ctx context.Context, postID string) (*Post, error)

	// UpdatePost updates an existing post.
	UpdatePost(ctx context.Context, post *Post) error

	// DeletePost removes a post from the system.
	DeletePost(ctx context.Context, postID string, userID string) error

	// ListPosts retrieves a list of posts based on filter criteria.
	ListPosts(ctx context.Context, filter *PostFilter) ([]*Post, error)

	// GetUserFeed returns posts for a user's feed.
	GetUserFeed(ctx context.Context, userID string, limit, offset int) ([]*Post, error)

	// GetTrendingPosts returns currently trending posts.
	GetTrendingPosts(ctx context.Context, limit int) ([]*Post, error)

	// AddReaction adds an emotional reaction to a post.
	AddReaction(ctx context.Context, postID string, userID string, reactionType ReactionType) error

	// RemoveReaction removes an emotional reaction from a post.
	RemoveReaction(ctx context.Context, postID string, userID string, reactionType ReactionType) error

	// GetUserReaction gets the current reaction of a user for a post.
	GetUserReaction(ctx context.Context, postID string, userID string) (*ReactionType, error)

	// GetReactedUsers returns users who reacted to a specific post with optional reaction type filter.
	GetReactedUsers(ctx context.Context, postID string, reactionType *ReactionType, limit, offset int) ([]string, error)

	// GetReactionCounts returns the count of each reaction type for a post.
	GetReactionCounts(ctx context.Context, postID string) (map[ReactionType]int, error)
}

PostManager defines the interface for managing posts in the system.

type PostManagerImpl

type PostManagerImpl struct {
	// contains filtered or unexported fields
}

PostManagerImpl implements the PostManager interface using a PostStore for persistence

func NewPostManager

func NewPostManager(store PostStore) *PostManagerImpl

NewPostManager creates a new instance of PostManagerImpl

func (*PostManagerImpl) AddReaction

func (m *PostManagerImpl) AddReaction(ctx context.Context, postID string, userID string, reactionType ReactionType) error

AddReaction adds an emotional reaction to a post

func (*PostManagerImpl) CreatePost

func (m *PostManagerImpl) CreatePost(ctx context.Context, post *Post) (string, error)

CreatePost creates a new post in the system

func (*PostManagerImpl) DeletePost

func (m *PostManagerImpl) DeletePost(ctx context.Context, postID string, userID string) error

DeletePost removes a post from the system

func (*PostManagerImpl) GetPost

func (m *PostManagerImpl) GetPost(ctx context.Context, postID string) (*Post, error)

GetPost retrieves a post by its ID

func (*PostManagerImpl) GetReactedUsers

func (m *PostManagerImpl) GetReactedUsers(ctx context.Context, postID string, reactionType *ReactionType, limit, offset int) ([]string, error)

GetReactedUsers returns users who reacted to a specific post with optional reaction type filter

func (*PostManagerImpl) GetReactionCounts

func (m *PostManagerImpl) GetReactionCounts(ctx context.Context, postID string) (map[ReactionType]int, error)

GetReactionCounts returns the count of each reaction type for a post

func (*PostManagerImpl) GetTrendingPosts

func (m *PostManagerImpl) GetTrendingPosts(ctx context.Context, limit int) ([]*Post, error)

GetTrendingPosts returns currently trending posts

func (*PostManagerImpl) GetUserFeed

func (m *PostManagerImpl) GetUserFeed(ctx context.Context, userID string, limit, offset int) ([]*Post, error)

GetUserFeed returns posts for a user's feed

func (*PostManagerImpl) GetUserReaction

func (m *PostManagerImpl) GetUserReaction(ctx context.Context, postID string, userID string) (*ReactionType, error)

GetUserReaction gets the current reaction of a user for a post

func (*PostManagerImpl) ListPosts

func (m *PostManagerImpl) ListPosts(ctx context.Context, filter *PostFilter) ([]*Post, error)

ListPosts retrieves a list of posts based on filter criteria

func (*PostManagerImpl) RemoveReaction

func (m *PostManagerImpl) RemoveReaction(ctx context.Context, postID string, userID string, reactionType ReactionType) error

RemoveReaction removes an emotional reaction from a post

func (*PostManagerImpl) UpdatePost

func (m *PostManagerImpl) UpdatePost(ctx context.Context, post *Post) error

UpdatePost updates an existing post

type PostModel

type PostModel struct {
	ID         string `gorm:"primaryKey"`
	UserID     string `gorm:"index"`
	Content    string
	Media      []MediaModel `gorm:"foreignKey:PostID"`
	Tags       []TagModel   `gorm:"many2many:post_tags;"`
	CreatedAt  time.Time
	UpdatedAt  time.Time
	Visibility string
	Comments   int
	Shares     int
}

PostModel is the GORM model for storing posts

type PostStore

type PostStore interface {
	// SavePost saves a new post or updates an existing post
	SavePost(ctx context.Context, post *Post) error

	// GetPost retrieves a post by its ID
	GetPost(ctx context.Context, postID string) (*Post, error)

	// DeletePost removes a post from the store
	DeletePost(ctx context.Context, postID string, userID string) error

	// ListPosts retrieves posts based on filter criteria
	ListPosts(ctx context.Context, filter *PostFilter) ([]*Post, error)

	// GetUserFeed retrieves posts for a user's feed
	GetUserFeed(ctx context.Context, userID string, limit, offset int) ([]*Post, error)

	// GetTrendingPosts retrieves currently trending posts
	GetTrendingPosts(ctx context.Context, limit int) ([]*Post, error)

	// SaveReaction saves a reaction to a post
	SaveReaction(ctx context.Context, postID string, userID string, reactionType ReactionType) error

	// DeleteReaction removes a reaction from a post
	DeleteReaction(ctx context.Context, postID string, userID string, reactionType ReactionType) error

	// GetUserReaction gets the current reaction of a user for a post
	GetUserReaction(ctx context.Context, postID string, userID string) (*ReactionType, error)

	// GetReactedUsers returns users who reacted to a specific post with optional reaction type filter
	GetReactedUsers(ctx context.Context, postID string, reactionType *ReactionType, limit, offset int) ([]string, error)

	// GetReactionCounts returns the count of each reaction type for a post
	GetReactionCounts(ctx context.Context, postID string) (map[ReactionType]int, error)
}

PostStore defines the interface for storing and retrieving posts

type ReactionModel

type ReactionModel struct {
	PostID       string `gorm:"primaryKey;index"`
	UserID       string `gorm:"primaryKey;index"`
	ReactionType uint8
	CreatedAt    time.Time
}

ReactionModel is the GORM model for storing user reactions to posts

type ReactionType

type ReactionType uint8

ReactionType represents different emotional reactions to posts using an efficient numeric type

const (
	ReactionNone  ReactionType = 0
	ReactionLike  ReactionType = 1
	ReactionLove  ReactionType = 2
	ReactionHaha  ReactionType = 3
	ReactionWow   ReactionType = 4
	ReactionSad   ReactionType = 5
	ReactionAngry ReactionType = 6
)

type TagModel

type TagModel struct {
	Name string `gorm:"primaryKey"`
}

TagModel is the GORM model for storing tags

type TimeRange

type TimeRange struct {
	Start time.Time
	End   time.Time
}

TimeRange represents a time range for filtering posts.

type UserReaction

type UserReaction struct {
	UserID       string
	ReactionType ReactionType
	CreatedAt    time.Time
}

UserReaction represents a user's reaction to a post

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL