Add event list
This commit is contained in:
parent
e9f219e391
commit
dfb0799672
|
@ -19,3 +19,33 @@ select {
|
|||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
padding-left: 0.5rem;
|
||||
border-left: 3px solid #aaa;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.events {
|
||||
h4 {
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.event {
|
||||
padding: 0.5rem;
|
||||
border-bottom: 1px solid #888;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
&:nth-child(2n) {
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
"""Add events
|
||||
|
||||
Revision ID: 132ee194cefe
|
||||
Revises: 5fb6db84ce55
|
||||
Create Date: 2017-11-09 09:26:18.763954
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '132ee194cefe'
|
||||
down_revision = '5fb6db84ce55'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.create_table('event',
|
||||
sa.Column('id', sa.Integer, primary_key=True),
|
||||
sa.Column('created', sa.DateTime, nullable=False),
|
||||
sa.Column('event_type', sa.Integer, nullable=False),
|
||||
sa.Column('old_status', sa.Integer, default=0),
|
||||
sa.Column('old_resolution', sa.Integer, default=0),
|
||||
sa.Column('new_status', sa.Integer, default=0),
|
||||
sa.Column('new_resolution', sa.Integer, default=0),
|
||||
sa.Column('user_id', sa.Integer, sa.ForeignKey("user.id"), nullable=False),
|
||||
sa.Column('ticket_id', sa.Integer, sa.ForeignKey("ticket.id"), nullable=False),
|
||||
sa.Column('comment_id', sa.Integer, sa.ForeignKey("ticket_comment.id"))
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_table('event')
|
|
@ -1,6 +1,6 @@
|
|||
from flask import Blueprint, render_template
|
||||
from flask_login import current_user
|
||||
from todosrht.types import Tracker
|
||||
from todosrht.types import Tracker, Event, EventType
|
||||
|
||||
html = Blueprint('html', __name__)
|
||||
|
||||
|
@ -12,5 +12,11 @@ def index():
|
|||
your_trackers = (Tracker.query
|
||||
.filter(Tracker.owner_id == current_user.id)
|
||||
.order_by(Tracker.updated.desc())).all()
|
||||
events = (Event.query
|
||||
.filter(Event.user_id == current_user.id)
|
||||
.order_by(Event.created.desc())
|
||||
.limit(10)).all()
|
||||
return render_template("dashboard.html",
|
||||
your_trackers=your_trackers)
|
||||
your_trackers=your_trackers,
|
||||
events=events,
|
||||
EventType=EventType)
|
||||
|
|
|
@ -5,7 +5,7 @@ from flask import session
|
|||
from flask_login import current_user
|
||||
from todosrht.decorators import loginrequired
|
||||
from todosrht.types import Tracker, User, Ticket, TicketStatus, TicketAccess, TicketSeen
|
||||
from todosrht.types import TicketComment, TicketResolution
|
||||
from todosrht.types import TicketComment, TicketResolution, Event, EventType
|
||||
from todosrht.blueprints.tracker import get_access, get_tracker
|
||||
from todosrht.email import notify
|
||||
from srht.config import cfg
|
||||
|
@ -92,6 +92,9 @@ def ticket_comment_POST(owner, name, ticket_id):
|
|||
else:
|
||||
comment = None
|
||||
|
||||
old_status = ticket.status
|
||||
old_resolution = ticket.resolution
|
||||
|
||||
if resolve and TicketAccess.edit in access:
|
||||
try:
|
||||
resolution = TicketResolution(int(resolution))
|
||||
|
@ -113,7 +116,7 @@ def ticket_comment_POST(owner, name, ticket_id):
|
|||
**valid.kwargs)
|
||||
|
||||
tracker.updated = datetime.utcnow()
|
||||
db.session.commit()
|
||||
db.session.flush()
|
||||
|
||||
if comment:
|
||||
ticket_url = url_for(".ticket_GET",
|
||||
|
@ -142,13 +145,35 @@ def ticket_comment_POST(owner, name, ticket_id):
|
|||
resolution=resolution.name if resolution else None,
|
||||
ticket_url=ticket_url.replace("%7E", "~")) # hack
|
||||
|
||||
def _add_event(sub):
|
||||
event = Event()
|
||||
event.event_type = 0
|
||||
event.user_id = sub.user_id
|
||||
event.ticket_id = ticket.id
|
||||
if comment:
|
||||
event.event_type |= EventType.comment
|
||||
event.comment_id = comment.id
|
||||
if ticket.status != old_status or ticket.resolution != old_resolution:
|
||||
event.event_type |= EventType.status_change
|
||||
event.old_status = old_status
|
||||
event.old_resolution = old_resolution
|
||||
event.new_status = ticket.status
|
||||
event.new_resolution = ticket.resolution
|
||||
db.session.add(event)
|
||||
|
||||
updated_users = set()
|
||||
for sub in tracker.subscriptions:
|
||||
updated_users.update([sub.user_id])
|
||||
_add_event(sub)
|
||||
if sub.user_id == current_user.id:
|
||||
subscribed = True
|
||||
continue
|
||||
_notify(sub)
|
||||
|
||||
for sub in ticket.subscriptions:
|
||||
if sub.user_id in updated_users:
|
||||
continue
|
||||
_add_event(sub)
|
||||
if sub.user_id == current_user.id:
|
||||
subscribed = True
|
||||
continue
|
||||
|
@ -159,6 +184,8 @@ def ticket_comment_POST(owner, name, ticket_id):
|
|||
sub.ticket_id = ticket.id
|
||||
sub.user_id = user.id
|
||||
db.session.add(sub)
|
||||
db.session.commit()
|
||||
_add_event(sub)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return redirect(ticket_url)
|
||||
|
|
|
@ -5,8 +5,9 @@ from flask import session
|
|||
from flask_login import current_user
|
||||
from todosrht.decorators import loginrequired
|
||||
from todosrht.email import notify
|
||||
from todosrht.types import Tracker, User, Ticket, TicketStatus, TicketAccess, TicketSeen
|
||||
from todosrht.types import Tracker, User, Ticket, TicketStatus, TicketAccess
|
||||
from todosrht.types import TicketComment, TicketResolution, TicketSubscription
|
||||
from todosrht.types import TicketSeen, Event, EventType
|
||||
from srht.config import cfg
|
||||
from srht.database import db
|
||||
from srht.validation import Validation
|
||||
|
@ -201,7 +202,7 @@ def tracker_submit_POST(owner, name):
|
|||
db.session.add(ticket)
|
||||
tracker.updated = datetime.utcnow()
|
||||
# TODO: Handle unique constraint failure (contention) and retry?
|
||||
db.session.commit()
|
||||
db.session.flush()
|
||||
|
||||
ticket_url = url_for("ticket.ticket_GET",
|
||||
owner="~" + tracker.owner.username,
|
||||
|
@ -209,6 +210,12 @@ def tracker_submit_POST(owner, name):
|
|||
ticket_id=ticket.scoped_id)
|
||||
|
||||
for sub in tracker.subscriptions:
|
||||
event = Event()
|
||||
event.event_type = EventType.created
|
||||
event.user_id = sub.user_id
|
||||
event.ticket_id = ticket.id
|
||||
db.session.add(event)
|
||||
|
||||
if sub.user_id == ticket.submitter_id:
|
||||
subscribed = True
|
||||
continue
|
||||
|
@ -225,7 +232,8 @@ def tracker_submit_POST(owner, name):
|
|||
sub.ticket_id = ticket.id
|
||||
sub.user_id = user.id
|
||||
db.session.add(sub)
|
||||
db.session.commit()
|
||||
|
||||
db.session.commit()
|
||||
|
||||
if another:
|
||||
session["another"] = True
|
||||
|
|
|
@ -1,23 +1,92 @@
|
|||
{% extends "todo.html" %}
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<h2>todo</h2>
|
||||
<p>Welcome to todo.sr.ht, {{ current_user.username }}!</p>
|
||||
<h2 style="margin-bottom: 1rem">todo</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<h3>Your Trackers</h3>
|
||||
{% if your_trackers %}
|
||||
<div class="tracker-list">
|
||||
{% for tracker in your_trackers %}
|
||||
<h4>{{ format_tracker_name(tracker, full=True) }}</h4>
|
||||
<span class="text-muted">Last active {{ tracker.updated | date }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p>
|
||||
Nothing here yet! Would you like to
|
||||
<a href="{{ url_for("tracker.create_GET") }}">create one</a>?
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{#
|
||||
<div class="col-md-4">
|
||||
<h3>Updated Tickets</h3>
|
||||
<div class="col-md-6">
|
||||
<h3>Recent Activity</h3>
|
||||
{% if events %}
|
||||
<div class="events">
|
||||
{% for event in events %}
|
||||
<div class="event">
|
||||
<h4>
|
||||
<a href="{{ url_for("ticket.ticket_GET",
|
||||
owner="~" + event.ticket.tracker.owner.username,
|
||||
name=event.ticket.tracker.name,
|
||||
ticket_id=event.ticket.scoped_id) }}">
|
||||
#{{event.ticket.scoped_id}}
|
||||
</a> {{ event.ticket.title }}
|
||||
<small class="pull-right">
|
||||
{{ event.created | date }}
|
||||
</small>
|
||||
</h4>
|
||||
{% if EventType.created in event.event_type %}
|
||||
<p>
|
||||
Ticket created by
|
||||
<a href="/~{{ event.ticket.submitter.username }}">
|
||||
~{{ event.ticket.submitter.username }}
|
||||
</a>
|
||||
on {{ format_tracker_name(event.ticket.tracker, full=True) }}:
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if EventType.comment in event.event_type %}
|
||||
<p>
|
||||
Comment by
|
||||
<a href="/~{{ event.ticket.submitter.username }}">
|
||||
~{{ event.ticket.submitter.username }}
|
||||
</a>
|
||||
on {{ format_tracker_name(event.ticket.tracker, full=True) }}:
|
||||
</p>
|
||||
{% endif %}
|
||||
<blockquote style="margin-bottom: 0">
|
||||
{% if event.comment %}
|
||||
{{ event.comment.text | md }}
|
||||
{% else %}
|
||||
{% if EventType.created in event.event_type %}
|
||||
{{ event.ticket.description | md }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</blockquote>
|
||||
{% if EventType.status_change in event.event_type %}
|
||||
<p>
|
||||
<strong class="text-success">
|
||||
{{ event.old_status.name.upper() }}
|
||||
{% if event.old_status == TicketStatus.resolved %}
|
||||
{{ event.old_resolution.name.upper() }}
|
||||
{% endif %}
|
||||
</strong>
|
||||
<span class="fa fa-arrow-right"></span>
|
||||
<strong class="text-success">
|
||||
{{ event.new_status.name.upper() }}
|
||||
{% if event.new_status == TicketStatus.resolved %}
|
||||
{{ event.new_resolution.name.upper() }}
|
||||
{% endif %}
|
||||
</strong>
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p>Nothing here yet!</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
#}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -6,3 +6,4 @@ from .ticketseen import TicketSeen
|
|||
from .ticket import Ticket
|
||||
from .ticketsubscription import TicketSubscription
|
||||
from .ticketcomment import TicketComment
|
||||
from .event import Event, EventType
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
import sqlalchemy as sa
|
||||
import sqlalchemy_utils as sau
|
||||
from srht.flagtype import FlagType
|
||||
from srht.database import Base
|
||||
from todosrht.types.ticketstatus import TicketStatus, TicketResolution
|
||||
from enum import IntFlag
|
||||
|
||||
class EventType(IntFlag):
|
||||
created = 1
|
||||
comment = 2
|
||||
status_change = 4
|
||||
|
||||
class Event(Base):
|
||||
"""
|
||||
Maps events on tickets to interested users.
|
||||
"""
|
||||
__tablename__ = 'event'
|
||||
id = sa.Column(sa.Integer, primary_key=True)
|
||||
created = sa.Column(sa.DateTime, nullable=False)
|
||||
|
||||
event_type = sa.Column(FlagType(EventType), nullable=False)
|
||||
|
||||
old_status = sa.Column(FlagType(TicketStatus), default=0)
|
||||
old_resolution = sa.Column(FlagType(TicketResolution), default=0)
|
||||
|
||||
new_status = sa.Column(FlagType(TicketStatus), default=0)
|
||||
new_resolution = sa.Column(FlagType(TicketResolution), default=0)
|
||||
|
||||
user_id = sa.Column(sa.Integer, sa.ForeignKey("user.id"), nullable=False)
|
||||
user = sa.orm.relationship("User", backref=sa.orm.backref("events"))
|
||||
|
||||
ticket_id = sa.Column(sa.Integer, sa.ForeignKey("ticket.id"), nullable=False)
|
||||
ticket = sa.orm.relationship("Ticket")
|
||||
|
||||
comment_id = sa.Column(sa.Integer, sa.ForeignKey("ticket_comment.id"))
|
||||
comment = sa.orm.relationship("TicketComment")
|
||||
|
||||
def __repr__(self):
|
||||
return '<Event {}>'.format(self.id)
|
Loading…
Reference in New Issue