feat: Complete chat system implementation and password reset enhancement

- Add comprehensive chat system with modern UI design
- Implement admin-based password reset system
- Fix template syntax errors and 500 server errors
- Add chat routes, API endpoints, and database models
- Enhance user interface with Tailwind CSS card-based design
- Implement community guidelines and quick action features
- Add responsive design for mobile and desktop compatibility
- Create support chat functionality with admin integration
- Fix JavaScript inheritance in base template
- Add database migration for chat system tables

Features:
 Modern chat interface with room management
 Admin-based password reset workflow
 Real-time chat with mobile app support
 Professional UI with gradient cards and hover effects
 Community guidelines and safety features
 Responsive design for all devices
 Error-free template rendering
This commit is contained in:
ske087
2025-08-09 20:44:25 +03:00
parent d1e2b95678
commit 1661f5f588
14 changed files with 2742 additions and 34 deletions

View File

@@ -305,3 +305,134 @@ class SentEmail(db.Model):
def __repr__(self):
return f'<SentEmail to={self.recipient} subject={self.subject} status={self.status}>'
class ChatRoom(db.Model):
__tablename__ = 'chat_rooms'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(200), nullable=False)
description = db.Column(db.Text)
room_type = db.Column(db.String(50), default='general') # general, post_discussion, admin_support, password_reset
is_private = db.Column(db.Boolean, default=False)
is_active = db.Column(db.Boolean, default=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
last_activity = db.Column(db.DateTime, default=datetime.utcnow)
# Foreign Keys
created_by_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
related_post_id = db.Column(db.Integer, db.ForeignKey('posts.id'), nullable=True) # For post discussions
# Relationships
created_by = db.relationship('User', backref='created_chat_rooms')
related_post = db.relationship('Post', backref='chat_rooms')
messages = db.relationship('ChatMessage', backref='room', lazy='dynamic', cascade='all, delete-orphan')
participants = db.relationship('ChatParticipant', backref='room', lazy='dynamic', cascade='all, delete-orphan')
def to_dict(self):
"""Convert to dictionary for API responses"""
return {
'id': self.id,
'name': self.name,
'description': self.description,
'room_type': self.room_type,
'is_private': self.is_private,
'is_active': self.is_active,
'created_at': self.created_at.isoformat() if self.created_at else None,
'last_activity': self.last_activity.isoformat() if self.last_activity else None,
'created_by': {
'id': self.created_by.id,
'nickname': self.created_by.nickname
} if self.created_by else None,
'related_post': {
'id': self.related_post.id,
'title': self.related_post.title
} if self.related_post else None,
'participant_count': self.participants.count(),
'message_count': self.messages.count()
}
def __repr__(self):
return f'<ChatRoom {self.name}>'
class ChatParticipant(db.Model):
__tablename__ = 'chat_participants'
id = db.Column(db.Integer, primary_key=True)
joined_at = db.Column(db.DateTime, default=datetime.utcnow)
last_seen = db.Column(db.DateTime, default=datetime.utcnow)
is_muted = db.Column(db.Boolean, default=False)
role = db.Column(db.String(50), default='member') # member, moderator, admin
# Foreign Keys
room_id = db.Column(db.Integer, db.ForeignKey('chat_rooms.id'), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
# Relationships
user = db.relationship('User', backref='chat_participations')
# Unique constraint
__table_args__ = (db.UniqueConstraint('room_id', 'user_id', name='unique_room_participant'),)
def to_dict(self):
"""Convert to dictionary for API responses"""
return {
'id': self.id,
'user': {
'id': self.user.id,
'nickname': self.user.nickname,
'is_admin': self.user.is_admin
},
'role': self.role,
'joined_at': self.joined_at.isoformat() if self.joined_at else None,
'last_seen': self.last_seen.isoformat() if self.last_seen else None,
'is_muted': self.is_muted
}
def __repr__(self):
return f'<ChatParticipant {self.user.nickname} in {self.room.name}>'
class ChatMessage(db.Model):
__tablename__ = 'chat_messages'
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.Text, nullable=False)
message_type = db.Column(db.String(50), default='text') # text, system, file, image
is_edited = db.Column(db.Boolean, default=False)
is_deleted = db.Column(db.Boolean, default=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# Foreign Keys
room_id = db.Column(db.Integer, db.ForeignKey('chat_rooms.id'), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
reply_to_id = db.Column(db.Integer, db.ForeignKey('chat_messages.id'), nullable=True) # For threaded replies
# Relationships
user = db.relationship('User', backref='chat_messages')
reply_to = db.relationship('ChatMessage', remote_side=[id], backref='replies')
def to_dict(self):
"""Convert to dictionary for API responses"""
return {
'id': self.id,
'content': self.content,
'message_type': self.message_type,
'is_edited': self.is_edited,
'is_deleted': self.is_deleted,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None,
'user': {
'id': self.user.id,
'nickname': self.user.nickname,
'is_admin': self.user.is_admin
},
'reply_to': {
'id': self.reply_to.id,
'content': self.reply_to.content[:100] + '...' if len(self.reply_to.content) > 100 else self.reply_to.content,
'user_nickname': self.reply_to.user.nickname
} if self.reply_to else None
}
def __repr__(self):
return f'<ChatMessage {self.id} by {self.user.nickname}>'