Skip to content

Commit

Permalink
Integrate nightly with master (#793)
Browse files Browse the repository at this point in the history
* Change status default value on Issue model

* Implemented create time-card, closes #758

* Enhancement code after review

* Enhancement code after review

* Enhancement code after review

* Add start_time, end_time, status and description to Item model, closes #768

* Enhancement code after review

* Enhancement code after review

* Implement the ADD verb on Item, closes #762

* Add a required import

* Added Null error check

* Enhancement code after review

* Implemented the update method on the time-card controller, closes #759

* Implemented delete event type, closes #746

* Implement LIST verb on Item, closes #764

* Added new test case

* The coding style is update

* Typo

* Fix the bug on creating release, closes #777

* Add release_cutoff column property to Project model, closes #776

* Add release_cutoff metadata on Project model

* Modified the release model, closes #780, closes #3, closes #32

* Add SEARCH verb on Issue

* Enhance query on searching Issue, closes #779

* Increased the coverage

* The event model is modified, closes #755, closes #724, closes #721

* Add description to full text search

* Implemented the search method on the member controller, clsoes #784

* Implemented the metadata method on the event controller

* Filtering issues by unread on searching, closes #788

* Reverted changes

* Removed the description field from event model

* Filtering issues by the triage phase id

* Implemented the get verb of timecard, closes #760

* Implemented the get verb of timecard, closes #760

* Implemented list verb for timecard, closes #761

* Resolved the conflict

* Add timecard metadata test

* Add timecard metadata test

* Add item metadata test

* Enhance imports

* Modified the event metadata

* Modified the project metadata

* Fixed a bug on the auditlog callback related to the rollback request

* Removing Redundant codes

* Resolved the conflict

* v0.42.0a7

* Add migrations

* Add item and time card migration

* v0.42.1a7

* Updated labels of item model

* Enhance coding style in migration versions
  • Loading branch information
mohammadsheikhian authored and pylover committed May 11, 2019
1 parent f1c5d4d commit a5f4ce7
Show file tree
Hide file tree
Showing 43 changed files with 1,626 additions and 161 deletions.
2 changes: 1 addition & 1 deletion dolphin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from .controllers.root import Root


__version__ = '0.36.0a4'
__version__ = '0.42.1a7'


class Dolphin(Application):
Expand Down
1 change: 1 addition & 0 deletions dolphin/controllers/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
'startDate',
'endDate',
'eventTypeId',
'repeat',
]


Expand Down
12 changes: 12 additions & 0 deletions dolphin/controllers/eventtype.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,15 @@ def update(self, id):
def list(self):
return DBSession.query(EventType)

@authorize
@json(prevent_form='709 Form Not Allowed')
@commit
def delete(self, id):
id = int_or_notfound(id)
event_type = DBSession.query(EventType).get(id)
if event_type is None:
raise HTTPNotFound()

DBSession.delete(event_type)
return event_type

47 changes: 44 additions & 3 deletions dolphin/controllers/issues.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import re
from datetime import datetime

from auditor import context as AuditLogContext
Expand All @@ -7,17 +8,18 @@
from restfulpy.authorization import authorize
from restfulpy.controllers import ModelRestController, JsonPatchControllerMixin
from restfulpy.orm import DBSession, commit
from sqlalchemy import and_, exists, select, func, join
from sqlalchemy import and_, exists, select, func, join, or_, Text, cast

from ..backends import ChatClient
from ..exceptions import StatusRoomMemberAlreadyExist, \
StatusRoomMemberNotFound, StatusChatRoomNotFound, StatusRelatedIssueNotFound, \
StatusIssueBugMustHaveRelatedIssue, StatusIssueNotFound
StatusIssueBugMustHaveRelatedIssue, StatusIssueNotFound, \
StatusQueryParameterNotInFormOrQueryString
from ..models import Issue, Subscription, Phase, Item, Member, Project, \
RelatedIssue, Subscribable, IssueTag, Tag
from ..validators import update_issue_validator, assign_issue_validator, \
issue_move_validator, unassign_issue_validator, issue_relate_validator, \
issue_unrelate_validator
issue_unrelate_validator, search_issue_validator
from .activity import ActivityController
from .files import FileController
from .phases import PhaseController
Expand All @@ -28,6 +30,9 @@
UNKNOWN_ASSIGNEE = -1


TRIAGE_PHASE_ID_PATTERN = re.compile(r'[(,\s]0[,\)\s]|^0$')


class IssueController(ModelRestController, JsonPatchControllerMixin):
__model__ = Issue

Expand Down Expand Up @@ -168,6 +173,12 @@ def list(self):
Item.phase_id,
value
)
if TRIAGE_PHASE_ID_PATTERN.search(value):
triage = DBSession.query(Issue) \
.outerjoin(Item, Item.issue_id == Issue.id) \
.filter(Item.id == None)
query = query.union(triage)

is_issue_item_joined = True

if 'phaseTitle' in context.query:
Expand Down Expand Up @@ -768,3 +779,33 @@ def _unsee_subscriptions(self, subscriptions):
for subscription in subscriptions:
subscription.seen_at = None

@authorize
@search_issue_validator
@json
@Issue.expose
def search(self):
query = context.form.get('query') or context.query.get('query')
if query is None:
raise StatusQueryParameterNotInFormOrQueryString()

query = f'%{query}%'
query = DBSession.query(Issue) \
.filter(or_(
Issue.title.ilike(query),
Issue.description.ilike(query),
cast(Issue.id, Text).ilike(query)
))

if 'unread' in context.query:
query = query \
.join(
Subscription,
and_(
Subscription.subscribable_id == Issue.id,
Subscription.seen_at.is_(None),
)
) \
.filter(Subscription.member_id == context.identity.id)

return query

6 changes: 6 additions & 0 deletions dolphin/controllers/items.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,9 @@ def get(self, id):

return item

@authorize
@json(prevent_form='709 Form Not Allowed')
@Item.expose
def list(self):
return DBSession.query(Item)

24 changes: 22 additions & 2 deletions dolphin/controllers/members.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
from restfulpy.controllers import ModelRestController
from restfulpy.orm import DBSession, commit
from sqlalchemy_media import store_manager
from sqlalchemy import or_

from ..models import Member, Skill, SkillMember, Organization, \
OrganizationMember, Group, GroupMember
from ..exceptions import StatusAlreadyGrantedSkill, StatusSkillNotGrantedYet
from ..exceptions import StatusAlreadyGrantedSkill, StatusSkillNotGrantedYet, \
StatusQueryParameterNotInFormOrQueryString
from ..validators import search_member_validator
from .organization import OrganizationController

from .skill import SkillController


Expand Down Expand Up @@ -69,6 +71,24 @@ def get(self, id):

return member

@authorize
@search_member_validator
@json
@Member.expose
def search(self):
query = context.form.get('query') or context.query.get('query')
if query is None:
raise StatusQueryParameterNotInFormOrQueryString()

query = f'%{query}%'
query = DBSession.query(Member) \
.filter(or_(
Member.title.ilike(query),
Member.name.ilike(query)
))

return query


class MemberSkillController(ModelRestController):
__model__ = Skill
Expand Down
27 changes: 11 additions & 16 deletions dolphin/controllers/releases.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
'description',
'status',
'cutoff',
'managerReferenceId',
'managerId',
'launchDate',
'groupId',
]
Expand All @@ -43,20 +43,17 @@ class ReleaseController(ModelRestController):
@commit
def create(self):
token = context.environ['HTTP_AUTHORIZATION']
member = DBSession.query(Member) \
.filter(
Member.reference_id == context.form['managerReferenceId']
) \
.one_or_none()
if member is None:
manager = DBSession.query(Member).get(context.form['managerId'])
if manager is None:
raise StatusManagerNotFound()

group = DBSession.query(Group).get(context.form.get('groupId'))
if group is None:
raise StatusGroupNotFound()

creator = Member.current()
release = Release()
release.manager_id = member.id
release.manager_id = manager.id
release.update_from_request()
if release.launch_date < release.cutoff:
raise StatusLaunchDateMustGreaterThanCutoffDate()
Expand All @@ -65,16 +62,16 @@ def create(self):
room = chat_client.create_room(
release.get_room_title(),
token,
member.access_token,
creator.access_token,
context.identity.reference_id
)
release.room_id = room['id']
try:
chat_client.add_member(
release.room_id,
member.reference_id,
manager.reference_id,
token,
member.access_token
creator.access_token
)

except StatusRoomMemberAlreadyExist:
Expand Down Expand Up @@ -116,11 +113,9 @@ def update(self, id):
f'"{form["title"]}" is already exists.'
)

manager_reference_id = context.form.get('managerReferenceId')
if manager_reference_id is not None:
member = DBSession.query(Member) \
.filter(Member.reference_id == manager_reference_id) \
.one_or_none()
manager_id = context.form.get('managerId')
if manager_id is not None:
member = DBSession.query(Member).get(manager_id)
if member is None:
raise StatusManagerNotFound()

Expand Down
36 changes: 34 additions & 2 deletions dolphin/controllers/timecard.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from nanohttp import json
from nanohttp import json, int_or_notfound, HTTPNotFound
from restfulpy.authorization import authorize
from restfulpy.controllers import ModelRestController
from restfulpy.orm import DBSession, commit

from ..exceptions import StatusEndDateMustBeGreaterThanStartDate
from ..models import Timecard
from ..validators import timecard_create_validator
from ..validators import timecard_create_validator, timecard_update_validator


class TimecardController(ModelRestController):
Expand All @@ -24,3 +24,35 @@ def create(self):
DBSession.add(time_card)
return time_card

@authorize
@json(prevent_form='709 Form Not Allowed')
def get(self, id):
id = int_or_notfound(id)
timecard = DBSession.query(Timecard).get(id)
if timecard is None:
raise HTTPNotFound()

return timecard

@authorize
@json(prevent_empty_form='708 Empty Form')
@timecard_update_validator
@commit
def update(self, id):
id = int_or_notfound(id)
timecard = DBSession.query(Timecard).get(id)
if timecard is None:
raise HTTPNotFound()

timecard.update_from_request()
if timecard.start_date > timecard.end_date:
raise StatusEndDateMustBeGreaterThanStartDate()

return timecard

@authorize
@json(prevent_form='709 Form Not Allowed')
@Timecard.expose
def list(self):
return DBSession.query(Timecard)

8 changes: 8 additions & 0 deletions dolphin/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,11 @@ class StatusStartDateIsNull(HTTPKnownStatus):
class StatusEndDateIsNull(HTTPKnownStatus):
status = '906 End Date Is Null'


class StatusRepeatNotInForm(HTTPKnownStatus):
status = '911 Repeat Not In Form'


class StatusQueryParameterNotInFormOrQueryString(HTTPKnownStatus):
status = '912 Query Parameter Not In Form Or Query String'

26 changes: 17 additions & 9 deletions dolphin/middleware_callback.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import traceback
from datetime import datetime

import ujson
from auditor.logentry import ChangeAttributeLogEntry, InstantiationLogEntry, \
AppendLogEntry, RemoveLogEntry, RequestLogEntry
from nanohttp import context
from nanohttp import context, HTTPStatus
from restfulpy.datetimehelpers import format_datetime

from dolphin.backends import ChatClient
Expand All @@ -18,7 +19,6 @@ def callback(audit_log):
if audit_log[-1].status == '200 OK' and len(audit_log) > 1:
chat_client = ChatClient()
member = Member.current()
# FIXME: We will rollback if cannot send a message successfully
for log in audit_log:
if isinstance(log, ChangeAttributeLogEntry):
message = dict(
Expand Down Expand Up @@ -55,11 +55,19 @@ def callback(audit_log):
)

if not isinstance(log, RequestLogEntry):
chat_client.send_message(
room_id=log.object_.room_id,
body=ujson.dumps(message),
mimetype=AUDIT_LOG_MIMETYPE,
token=context.environ['HTTP_AUTHORIZATION'],
x_access_token=member.access_token,
)
try:
chat_client.send_message(
room_id=log.object_.room_id,
body=ujson.dumps(message),
mimetype=AUDIT_LOG_MIMETYPE,
token=context.environ['HTTP_AUTHORIZATION'],
x_access_token=member.access_token,
)

# This exception passed because after consulting with
# Mr.Mardani, decision made: This exception will be
# resolved when the dolphin and jaguar merge together
except HTTPStatus:
traceback.print_exc()
pass

47 changes: 47 additions & 0 deletions dolphin/migration/versions/07d212f7a1d7_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""empty message
Revision ID: 07d212f7a1d7
Revises: 26d0e0ee2536
Create Date: 2019-05-02 12:20:25.784006
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '07d212f7a1d7'
down_revision = '26d0e0ee2536'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.execute(
"CREATE TYPE event_repeat AS ENUM ('yearly', 'monthly', 'never');"
)
op.execute(
"ALTER TABLE event ADD repeat event_repeat;"
)
op.drop_column('event', 'description')
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.execute(
"ALTER TABLE event DROP COLUMN repeat;"
)
op.execute(
"DROP TYPE event_repeat;"
)
op.add_column(
'event',
sa.Column(
'description',
sa.VARCHAR(),
autoincrement=False,
nullable=True
)
)
# ### end Alembic commands ###

Loading

0 comments on commit a5f4ce7

Please sign in to comment.