Skip to content

Commit

Permalink
Merge pull request #2 from marvelapp/feature/merge-company-and-person…
Browse files Browse the repository at this point in the history
…al-projects

Feature/merge company and personal projects
  • Loading branch information
maximedegreve authored Apr 5, 2018
2 parents 544a214 + 20a549e commit 5d6f7e7
Show file tree
Hide file tree
Showing 10 changed files with 196 additions and 71 deletions.
15 changes: 15 additions & 0 deletions Public/styles/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ a{
flex-direction: row;
align-items: stretch;
height: 100vh;
min-height: 840px;

}

#home .container > div {
Expand Down Expand Up @@ -377,3 +379,16 @@ only screen and (min-device-pixel-ratio: 1.5) {
background-repeat: no-repeat;
}
}


@media (max-height: 900px) {

#home .main .robot-area .robot{
background-size: 258px 223px;
background-repeat: no-repeat;
width: 258px;
height: 223px;
margin-left: -155px;
}

}
22 changes: 13 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,21 @@

<img src="/Public/images/github-header.png?raw=true" width="888">

Post & create [Marvel](https://marvelapp.com) projects directly from Slack, written in Swift (Vapor).
BotBot is an open-source Slackbot for [Marvel](https://marvelapp.com) - a design collaboration platform that brings ideas to life.

Build your own integration using the [Marvel API](https://marvelapp.com/developers/).
[Go to BotBot and install](https://botbot.marvelapp.com)

[Try it out](https://botbot.marvelapp.com)
BotBot allows you and your team to create, view and manage Marvel projects directly inside of Slack.

**Why it's so amazing**
* Anyone in your team can quickly pull up a list of Marvel projects without leaving Slack by typing ```/projects```
* Create a project in seconds by typing ```/create-project```
* Add people to projects by typing ```/add-people```
* Or just grab the code and roll your own bot

Built using the Marvel GraphQL API - [get started here](https://marvelapp.com/developers/).

Questions? Hit us up on [Twitter](http://twitter.com/marvelapp)

## 🎒 Before building (dependencies)
* Install [Xcode](https://developer.apple.com/xcode/)
Expand All @@ -27,9 +37,3 @@ Build your own integration using the [Marvel API](https://marvelapp.com/develope

## 📖 Documentation
Visit the Vapor web framework's [documentation](http://docs.vapor.codes) for instructions on how to use this package.

## 💧 Community
Join the welcoming community of fellow Vapor developers in [Slack](http://vapor.team).

## 🔧 Compatibility
This package has been tested on macOS and Heroku.
6 changes: 3 additions & 3 deletions Resources/Views/home.leaf
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<div class="main">

<div class="github animated fadeIn">
<iframe src="https://ghbtns.com/github-btn.html?user=marvelapp&repo=MarvelSlackBot&type=watch&count=true" frameborder="0" scrolling="0" width="170px" height="20px"></iframe>
<iframe src="https://ghbtns.com/github-btn.html?user=marvelapp&repo=BotBot&type=watch&count=true" frameborder="0" scrolling="0" width="170px" height="20px"></iframe>
</div>

<div class="content">
Expand All @@ -24,7 +24,7 @@
<!-- Middle -->
<div class="animated slideInDown">
<h1>A Slack bot for Marvel</h1>
<h2>Post & create Marvel projects directly from Slack</h2>
<h2>Create and view Marvel projects directly in Slack</h2>
<a class="button" href="#(connect-url)">Connect with <img src="/images/marvel-logo.svg" style="margin-left:5px"></a>
</div>

Expand Down Expand Up @@ -58,7 +58,7 @@
</div>

<div class="footer-area animated fadeIn">
<a href="https://marvelapp.com/developers/" target="_blank">Uses the Marvel API</a>
<a href="https://marvelapp.com/developers/" target="_blank">Created with the Marvel API</a>
</div>

<div class="background-pattern"></div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,3 @@ final class SlackAuthenticationController {
}

}

18 changes: 13 additions & 5 deletions Sources/App/Controllers/Slack/SlackExternalController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,6 @@ final class SlackExternalController {
return try Error.with(name: .noMarvelToken)
}

// Get company members

let projectsJSON = try projectsInSlackFormat(request: request, marvelAccessToken: marvelToken)

// Filter on what the user is searching for in the field on Slack
Expand Down Expand Up @@ -155,22 +153,32 @@ final class SlackExternalController {

func projectsInSlackFormat(request: Request, marvelAccessToken: String, displayProperty: String = "text") throws -> [JSON] {

let result = try Marvel(droplet: drop).projects(accessToken: marvelAccessToken)
let result = try Marvel(droplet: drop).projectsIncludingCompany(accessToken: marvelAccessToken)

guard let projectsArray = result.data["data"]?["user"]?["projects"]?["edges"]?.array else {
guard var projectsArray = result.data["data"]?["user"]?["projects"]?["edges"]?.array else {
throw Abort.badRequest
}

// Check if users has company projects
if let companyProjectsArray = result.data["data"]?["user"]?["company"]?["projects"]?["edges"]?.array {
projectsArray.append(contentsOf: companyProjectsArray)
}

var projectsNode = [MarvelProject]()
for project in projectsArray{
let project = MarvelProject(with: project["node"])
projectsNode.append(project)
}

// Clear duplicates as company projects might include personal projects...
let filteredProjectsNode = projectsNode.filterDuplicates {
$0.pk == $1.pk

}

// Map to a readable Slack format

let projectsJSON = try projectsNode.map { (project) -> JSON in
let projectsJSON = try filteredProjectsNode.map { (project) -> JSON in

let json = try JSON(node: [
displayProperty: project.name,
Expand Down
31 changes: 10 additions & 21 deletions Sources/App/Controllers/Slack/SlackProjectsController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,45 +74,34 @@ final class SlackProjectsController {
return try Error.with(name: .noMarvelToken)
}

let projects = try Marvel(droplet: drop).projects(accessToken: marvelToken)

guard let projectsArray = projects.data["data"]?["user"]?["projects"]?["edges"]?.array else {
return try Error.with(name: .general)
}

var projectsNode = [MarvelProject]()
for project in projectsArray{
let project = MarvelProject(with: project["node"])
projectsNode.append(project)
}

let project = projectsNode.filter { (project) -> Bool in
return project.pk == value
}.first
let projects = try Marvel(droplet: drop).project(pk: value, accessToken: marvelToken)

guard let projectFound = project else {
guard let projectDic = projects.data["data"]?["project"] else {
return try Error.with(name: .general)
}

let collaborators = projectFound.collaborators.flatMap { (collab) -> String? in
let project = MarvelProject(with: projectDic)

let collaborators = project.collaborators.compactMap { (collab) -> String? in
return collab.username
}.joined(separator: ", ")
let collabWord = projectFound.collaborators.count > 1 ? "👧 \(projectFound.collaborators.count) collaborators" : "👧 1 collaborator"
let collabWord = project.collaborators.count > 1 ? "👧 \(project.collaborators.count) collaborators" : "👧 1 collaborator"

return try JSON(node: [
"response_type": "in_channel",
"replace_original": false,
"delete_original": true,
"attachments": [
[
"title": projectFound.name,
"title_link": projectFound.prototypeUrl,
"thumb_url": projectFound.screens.first?.content?.url ?? "",
"title": project.name,
"title_link": project.prototypeUrl,
"thumb_url": project.screens.first?.content?.url ?? "",
"footer": "Marvel Prototyping",
"fields": [
[
"title": "⏱ Last updated",
"value": projectFound.lastModified.since().capitalizingFirstLetter(),
"value": project.lastModified.since().capitalizingFirstLetter(),
"short": true
],
[
Expand Down
28 changes: 28 additions & 0 deletions Sources/App/Extensions/Array.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// Array.swift
// App
//
// Created by Maxime De Greve on 16/02/2018.
//

import Foundation

extension Array {

func filterDuplicates(includeElement: @escaping (_ lhs: Element, _ rhs: Element) -> Bool) -> [Element] {

var results = [Element]()

forEach { (element) in

let existingElements = results.filter {
return includeElement(element, $0)
}

if existingElements.count == 0 {
results.append(element)
}
}
return results
}
}
130 changes: 104 additions & 26 deletions Sources/App/Tools/Marvel/GraphQueries.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,42 +42,76 @@ final class GraphQueries {
url
}
query {
user {
projects(first: 40) {
{
user {
company {
projects(first: 40) {
edges {
node {
pk
name
prototypeUrl
lastModified
collaborators {
edges {
node {
pk
username
email
}
}
}
screens(first: 2) {
edges {
node {
name
uuid
modifiedAt
content {
__typename
...image
}
}
}
}
}
}
}
}
projects(first: 40) {
edges {
node {
pk
name
prototypeUrl
lastModified
collaborators {
edges {
node {
pk
username
email
}
}
}
screens(first: 2) {
edges {
node {
name
prototypeUrl
lastModified
collaborators {
edges {
node {
pk
username
email
}
}
}
screens(first: 2) {
edges {
node {
name
uuid
modifiedAt
content {
__typename
... image
}
}
}
uuid
modifiedAt
content {
__typename
...image
}
}
}
}
}
}
}
}
}
"""

static func createProject(name: String) -> String{
Expand All @@ -96,6 +130,50 @@ final class GraphQueries {

}

static func project(pk: Int) -> String{

return """
fragment image on ImageScreen {
filename
url
}
query {
project(pk: \(pk)) {
pk
name
prototypeUrl
lastModified
collaborators {
edges {
node {
pk
username
email
}
}
}
screens(first: 2) {
edges {
node {
name
uuid
modifiedAt
content {
__typename
...image
}
}
}
}
}
}
"""

}

static func addCollaboratorToProject(email: String, projectPk: Int) -> String{

return """
Expand Down
Loading

0 comments on commit 5d6f7e7

Please sign in to comment.