commit
336b1f2ee4
|
@ -2,7 +2,7 @@
|
|||
|
||||
# The selene-shared parent image contains all the common Docker configs for
|
||||
# all Selene apps and services see the "shared" directory in this repository.
|
||||
FROM docker.mycroft.ai/selene-shared:latest
|
||||
FROM docker.mycroft.ai/selene-shared:2018.4
|
||||
LABEL description="Run the API for the Mycroft marketplace"
|
||||
|
||||
# Use pipenv to install the package's dependencies in the container
|
|
@ -4,14 +4,14 @@ verify_ssl = true
|
|||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
flask-restful = "*"
|
||||
flask = "*"
|
||||
requests = "*"
|
||||
certifi = "*"
|
||||
flask-restful = "*"
|
||||
pyjwt = "*"
|
||||
uwsgi = "*"
|
||||
markdown = "*"
|
||||
|
||||
[dev-packages]
|
||||
selene-util = {path = "./../../../../shared"}
|
||||
|
||||
[requires]
|
||||
python_version = "3.7"
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "7cf1dde24d5a966645f3e49d93dde93dad42c6b6fa62f9b254b79d6b58e93e06"
|
||||
"sha256": "b4d53000e056d8f0a03cde9f3a8a2d4a96d19309908aee9020357cc3800c52cc"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
|
@ -18,18 +18,17 @@
|
|||
"default": {
|
||||
"aniso8601": {
|
||||
"hashes": [
|
||||
"sha256:7849749cf00ae0680ad2bdfe4419c7a662bef19c03691a19e008c8b9a5267802",
|
||||
"sha256:94f90871fcd314a458a3d4eca1c84448efbd200e86f55fe4c733c7a40149ef50"
|
||||
"sha256:547e7bc88c19742e519fb4ca39f4b8113fdfb8fca322e325f16a8bfc6cfc553c",
|
||||
"sha256:e7560de91bf00baa712b2550a2fdebf0188c5fce2fcd1162fbac75c19bb29c95"
|
||||
],
|
||||
"version": "==3.0.2"
|
||||
"version": "==4.0.1"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:376690d6f16d32f9d1fe8932551d80b23e9d393a8578c5633a2ed39a64861638",
|
||||
"sha256:456048c7e371c089d0a77a5212fb37a2c2dce1e24146e3b7e0261736aaeaa22a"
|
||||
"sha256:339dc09518b07e2fa7eda5450740925974815557727d6bd35d319c1524a04a4c",
|
||||
"sha256:6d58c986d22b038c8c0df30d639f23a3e6d172a05c3583e766f4c0b785c0986a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2018.8.24"
|
||||
"version": "==2018.10.15"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
|
@ -43,7 +42,6 @@
|
|||
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
|
||||
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version != '3.3.*' and python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.1.*'",
|
||||
"version": "==7.0"
|
||||
},
|
||||
"flask": {
|
||||
|
@ -71,9 +69,10 @@
|
|||
},
|
||||
"itsdangerous": {
|
||||
"hashes": [
|
||||
"sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519"
|
||||
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
|
||||
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
|
||||
],
|
||||
"version": "==0.24"
|
||||
"version": "==1.1.0"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
|
@ -82,6 +81,14 @@
|
|||
],
|
||||
"version": "==2.10"
|
||||
},
|
||||
"markdown": {
|
||||
"hashes": [
|
||||
"sha256:c00429bd503a47ec88d5e30a751e147dcb4c6889663cd3e2ba0afe858e009baa",
|
||||
"sha256:d02e0f9b04c500cde6637c11ad7c72671f359b87b9fe924b2383649d8841db7c"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.0.1"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"
|
||||
|
@ -98,18 +105,18 @@
|
|||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
"sha256:a061aa0a9e06881eb8b3b2b43f05b9439d6583c206d0a6c340ff72a7b6669053",
|
||||
"sha256:ffb9ef1de172603304d9d2819af6f5ece76f2e85ec10692a524dd876e72bf277"
|
||||
"sha256:31cb35c89bd7d333cd32c5f278fca91b523b0834369e757f4c5641ea252236ca",
|
||||
"sha256:8e0f8568c118d3077b46be7d654cc8167fa916092e28320cde048e54bfc9f1e6"
|
||||
],
|
||||
"version": "==2018.5"
|
||||
"version": "==2018.7"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1",
|
||||
"sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a"
|
||||
"sha256:99dcfdaaeb17caf6e526f32b6a7b780461512ab3f1d992187801694cba42770c",
|
||||
"sha256:a84b8c9ab6239b578f22d1c21d51b696dcfe004032bb80ea832398d6909d7279"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.19.1"
|
||||
"version": "==2.20.0"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
|
@ -120,11 +127,10 @@
|
|||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf",
|
||||
"sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5"
|
||||
"sha256:41c3db2fc01e5b907288010dec72f9d0a74e37d6994e6eb56849f59fea2265ae",
|
||||
"sha256:8819bba37a02d143296a4d032373c4dd4aca11f6d4c9973335ca75f9c8475f59"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version != '3.1.*' and python_version != '3.3.*' and python_version < '4' and python_version != '3.0.*' and python_version != '3.2.*'",
|
||||
"version": "==1.23"
|
||||
"version": "==1.24"
|
||||
},
|
||||
"uwsgi": {
|
||||
"hashes": [
|
||||
|
@ -141,9 +147,5 @@
|
|||
"version": "==0.14.1"
|
||||
}
|
||||
},
|
||||
"develop": {
|
||||
"selene-util": {
|
||||
"path": "./../../../../shared"
|
||||
}
|
||||
}
|
||||
"develop": {}
|
||||
}
|
|
@ -12,19 +12,19 @@ from market_api.endpoints import (
|
|||
)
|
||||
|
||||
# Define the Flask application
|
||||
marketplace = Flask(__name__)
|
||||
marketplace.config.from_object(get_config_location())
|
||||
market = Flask(__name__)
|
||||
market.config.from_object(get_config_location())
|
||||
|
||||
# Define the API and its endpoints.
|
||||
marketplace_api = Api(marketplace)
|
||||
marketplace_api.add_resource(AvailableSkillsEndpoint, '/api/skill/available')
|
||||
marketplace_api.add_resource(
|
||||
market_api = Api(market)
|
||||
market_api.add_resource(AvailableSkillsEndpoint, '/api/skill/available')
|
||||
market_api.add_resource(
|
||||
SkillDetailEndpoint,
|
||||
'/api/skill/detail/<skill_name>'
|
||||
)
|
||||
marketplace_api.add_resource(SkillInstallEndpoint, '/api/skill/install')
|
||||
marketplace_api.add_resource(
|
||||
market_api.add_resource(SkillInstallEndpoint, '/api/skill/install')
|
||||
market_api.add_resource(
|
||||
SkillInstallationsEndpoint,
|
||||
'/api/skill/installations'
|
||||
)
|
||||
marketplace_api.add_resource(UserEndpoint, '/api/user')
|
||||
market_api.add_resource(UserEndpoint, '/api/user')
|
|
@ -10,7 +10,7 @@ class BaseConfig:
|
|||
"""Base configuration."""
|
||||
DEBUG = False
|
||||
SECRET_KEY = os.environ['JWT_SECRET']
|
||||
SELENE_BASE_URL = os.environ['SELENE_BASE_URL']
|
||||
SERVICE_BASE_URL = os.environ['SERVICE_BASE_URL']
|
||||
TARTARUS_BASE_URL = os.environ['TARTARUS_BASE_URL']
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ class AvailableSkillsEndpoint(SeleneEndpoint):
|
|||
repository. The JSON object contains metadata about each skill.
|
||||
"""
|
||||
skill_service_response = service_request.get(
|
||||
self.config['SELENE_BASE_URL'] + '/skill/all'
|
||||
self.config['SERVICE_BASE_URL'] + '/skill/all'
|
||||
)
|
||||
if skill_service_response.status_code != HTTPStatus.OK:
|
||||
self._check_for_service_errors(skill_service_response)
|
|
@ -34,7 +34,7 @@ class SkillDetailEndpoint(SeleneEndpoint):
|
|||
def _get_skill_details(self) -> RepositorySkill:
|
||||
"""Build the data to include in the response."""
|
||||
skill_service_response = service_request.get(
|
||||
self.config['SELENE_BASE_URL'] + '/skill/name/' + self.skill_name
|
||||
self.config['SERVICE_BASE_URL'] + '/skill/name/' + self.skill_name
|
||||
)
|
||||
self._check_for_service_errors(skill_service_response)
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
swagger: '2.0'
|
||||
info:
|
||||
description: >-
|
||||
The marketplace is where users can access the skills available to install on
|
||||
their devices. In the future, other products like voices and hardware will
|
||||
be available through the store.
|
||||
version: '2018.3'
|
||||
title: Mycroft Marketplace
|
||||
host: market.mycroft.ai
|
||||
basePath: /api
|
||||
tags:
|
||||
- name: skill
|
||||
description: >-
|
||||
Browse information about available skills and manage skills on your
|
||||
devices.
|
||||
schemes:
|
||||
- https
|
||||
paths:
|
||||
/skill/available:
|
||||
get:
|
||||
tags:
|
||||
- skill
|
||||
summary: Retrieve all available skills for devices using Mycroft.
|
||||
description: >-
|
||||
The data retrieved is based on the skill metadata found in the
|
||||
mycroft-skills-data Github repository.
|
||||
parameters:
|
||||
- name: search
|
||||
in: query
|
||||
description: >-
|
||||
Filter skills by comparing the value of this parameter to a skill's
|
||||
title, summary, description, categories and tags. All skills are
|
||||
returned when this parameter is omitted.
|
||||
required: false
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/SkillSummary'
|
||||
'/skill/detail/{skillName}':
|
||||
get:
|
||||
tags:
|
||||
- skill
|
||||
summary: Retrieve more detailed information about a selected skill.
|
||||
description: >-
|
||||
This endpoint provides more information about a skill than is provided
|
||||
in the available skills endpoint.
|
||||
parameters:
|
||||
- name: skillName
|
||||
in: path
|
||||
description: Unique name of the skill to return.
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/SkillDetail'
|
||||
'/skill/installations':
|
||||
get:
|
||||
tags:
|
||||
- skill
|
||||
summary: Retrieve the installation status of skills for a user.
|
||||
description: >-
|
||||
When a user is logged in, this endpoint will return the skills known by that user's device(s). It will communicate the installation status of each skill as it relates to a user's devices.
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/Installations'
|
||||
definitions:
|
||||
SkillSummary:
|
||||
description: >-
|
||||
Subset of the skill metadata used for generating a list of available
|
||||
skills.
|
||||
type: object
|
||||
properties:
|
||||
icon:
|
||||
$ref: '#/definitions/Icon'
|
||||
iconImage:
|
||||
description: >-
|
||||
Url to an icon image. When provided it will take precedence over the
|
||||
value of the icon field.
|
||||
format: uri
|
||||
type: string
|
||||
isMycroftMade:
|
||||
description: Denotes a skill that is written by someone on the Mycroft team.
|
||||
type: boolean
|
||||
isSystemSkill:
|
||||
description: >-
|
||||
System skills are treated differently than others in that they are all
|
||||
installed on a device by default and cannot be installed. Volume
|
||||
control is an example.
|
||||
type: boolean
|
||||
marketCategory:
|
||||
description: >-
|
||||
A skill may have many categories. The first category defined is used
|
||||
when displaying the list of available skills.
|
||||
example: Music
|
||||
type: string
|
||||
name:
|
||||
description: >-
|
||||
uniquely identifying name of skill that is the same as the skill's
|
||||
submodule name in the mycroft-skills Github repository
|
||||
example: spotify
|
||||
type: string
|
||||
summary:
|
||||
description: A short phrase describing the skill's function
|
||||
example: Listen to music from your Spotify account
|
||||
type: string
|
||||
title:
|
||||
example: Spotify
|
||||
type: string
|
||||
trigger:
|
||||
description: Example of a voice command that triggers the skill.
|
||||
example: Play Rush on Spotify
|
||||
type: string
|
||||
SkillDetail:
|
||||
type: object
|
||||
properties:
|
||||
categories:
|
||||
description: All categories related to the skill
|
||||
example:
|
||||
- Music
|
||||
- Entertainment
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
credits:
|
||||
$ref: '#/definitions/Credits'
|
||||
description:
|
||||
description: Detailed description of the skill and its capabilities.
|
||||
type: string
|
||||
icon:
|
||||
$ref: '#/definitions/Icon'
|
||||
iconImage:
|
||||
description: >-
|
||||
Url to an icon image. When provided it will take precedence over the
|
||||
value of the icon field.
|
||||
format: uri
|
||||
type: string
|
||||
isSystemSkill:
|
||||
description: >-
|
||||
System skills are treated differently than others in that they are all
|
||||
installed on a device by default and cannot be installed. Volume
|
||||
control is an example.
|
||||
type: boolean
|
||||
marketCategory:
|
||||
description: >-
|
||||
A skill may have many categories. The first category defined is used
|
||||
when displaying the list of available skills.
|
||||
example: Music
|
||||
type: string
|
||||
name:
|
||||
description: >-
|
||||
uniquely identifying name of skill that is the same as the skill's
|
||||
submodule name in the mycroft-skills Github repository
|
||||
example: Spotify
|
||||
type: string
|
||||
platforms:
|
||||
description: Lists the platforms this skill can run on. Defaults to "any"
|
||||
example:
|
||||
- Mark I
|
||||
- Mark II
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
repositoryUrl:
|
||||
description: A URL representing the Github page for that skill.
|
||||
summary:
|
||||
description: A short phrase describing the skill's function
|
||||
example: Listen to music from your Spotify account
|
||||
type: string
|
||||
title:
|
||||
example: Spotify
|
||||
type: string
|
||||
triggers:
|
||||
description: Examples of a voice commands that trigger the skill.
|
||||
example:
|
||||
- Play Rush on Spotify
|
||||
- Play Discover Weekly
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
Credits:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
example: Mycroft AI
|
||||
type: string
|
||||
githubId:
|
||||
type: string
|
||||
Icon:
|
||||
description: >-
|
||||
Identifies a FontAwesome icon representing the skill and the color of the
|
||||
icon
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
description: Name of the icon as defined in the FontAwesome library
|
||||
example: music
|
||||
type: string
|
||||
color:
|
||||
description: The color that will be applied to the icon in the UI.
|
||||
example: '#22a7f0'
|
||||
type: string
|
||||
format: hex
|
||||
Installations:
|
||||
description: >-
|
||||
Install status of all skills on a user's device(s) and the reason for installation failures, if there are any.
|
||||
properties:
|
||||
installStatuses:
|
||||
type: object
|
||||
failureReasons:
|
||||
type: object
|
|
@ -1,5 +1,5 @@
|
|||
[uwsgi]
|
||||
master = true
|
||||
module = market_api.api:marketplace
|
||||
module = market_api.api:market
|
||||
processes = 4
|
||||
socket = :7101
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# The selene-shared parent image contains all the common Docker configs for
|
||||
# all Selene apps and services see the "shared" directory in this repository.
|
||||
FROM docker.mycroft.ai/selene-shared:latest
|
||||
FROM docker.mycroft.ai/selene-shared:2018.4
|
||||
LABEL description="Run the API for the Mycroft login screen"
|
||||
|
||||
# Use pipenv to install the package's dependencies in the container
|
||||
|
@ -16,7 +16,7 @@ RUN rm Pipfile
|
|||
RUN rm Pipfile.lock
|
||||
|
||||
# Load the skill service application to the image
|
||||
COPY login_api /opt/selene/login_api
|
||||
COPY sso_api /opt/selene/sso_api
|
||||
WORKDIR /opt/selene/
|
||||
|
||||
EXPOSE 7102
|
|
@ -12,7 +12,6 @@ certifi = "*"
|
|||
uwsgi = "*"
|
||||
|
||||
[dev-packages]
|
||||
selene-util = {path = "./../../../../shared"}
|
||||
|
||||
[requires]
|
||||
python_version = "3.7"
|
|
@ -0,0 +1,171 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "a9e06c9e1f71a037b615d9ad628b9fe9954e7fa97e0e0460626c8aa59ecb0ccf"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.7"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"aniso8601": {
|
||||
"hashes": [
|
||||
"sha256:547e7bc88c19742e519fb4ca39f4b8113fdfb8fca322e325f16a8bfc6cfc553c",
|
||||
"sha256:e7560de91bf00baa712b2550a2fdebf0188c5fce2fcd1162fbac75c19bb29c95"
|
||||
],
|
||||
"version": "==4.0.1"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:339dc09518b07e2fa7eda5450740925974815557727d6bd35d319c1524a04a4c",
|
||||
"sha256:6d58c986d22b038c8c0df30d639f23a3e6d172a05c3583e766f4c0b785c0986a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2018.10.15"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
|
||||
],
|
||||
"version": "==3.0.4"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
|
||||
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
|
||||
],
|
||||
"version": "==7.0"
|
||||
},
|
||||
"flask": {
|
||||
"hashes": [
|
||||
"sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48",
|
||||
"sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.0.2"
|
||||
},
|
||||
"flask-restful": {
|
||||
"hashes": [
|
||||
"sha256:5795519501347e108c436b693ff9a4d7b373a3ac9069627d64e4001c05dd3407",
|
||||
"sha256:e2f1b8063de3944b94c7f8be5cee4d2161db0267c54c5b757d875295061776fa"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.3.6"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e",
|
||||
"sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16"
|
||||
],
|
||||
"version": "==2.7"
|
||||
},
|
||||
"itsdangerous": {
|
||||
"hashes": [
|
||||
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
|
||||
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
|
||||
],
|
||||
"version": "==1.1.0"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
|
||||
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
|
||||
],
|
||||
"version": "==2.10"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432",
|
||||
"sha256:130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b",
|
||||
"sha256:19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9",
|
||||
"sha256:1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af",
|
||||
"sha256:1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834",
|
||||
"sha256:1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd",
|
||||
"sha256:1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d",
|
||||
"sha256:31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7",
|
||||
"sha256:3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b",
|
||||
"sha256:4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3",
|
||||
"sha256:525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c",
|
||||
"sha256:52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2",
|
||||
"sha256:52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7",
|
||||
"sha256:5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36",
|
||||
"sha256:5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1",
|
||||
"sha256:5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e",
|
||||
"sha256:7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1",
|
||||
"sha256:83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c",
|
||||
"sha256:857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856",
|
||||
"sha256:98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550",
|
||||
"sha256:bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492",
|
||||
"sha256:d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672",
|
||||
"sha256:e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401",
|
||||
"sha256:edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6",
|
||||
"sha256:efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6",
|
||||
"sha256:f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c",
|
||||
"sha256:f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd",
|
||||
"sha256:fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1"
|
||||
],
|
||||
"version": "==1.1.0"
|
||||
},
|
||||
"pyjwt": {
|
||||
"hashes": [
|
||||
"sha256:30b1380ff43b55441283cc2b2676b755cca45693ae3097325dea01f3d110628c",
|
||||
"sha256:4ee413b357d53fd3fb44704577afac88e72e878716116270d722723d65b42176"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.6.4"
|
||||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
"sha256:31cb35c89bd7d333cd32c5f278fca91b523b0834369e757f4c5641ea252236ca",
|
||||
"sha256:8e0f8568c118d3077b46be7d654cc8167fa916092e28320cde048e54bfc9f1e6"
|
||||
],
|
||||
"version": "==2018.7"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:65b3a120e4329e33c9889db89c80976c5272f56ea92d3e74da8a463992e3ff54",
|
||||
"sha256:ea881206e59f41dbd0bd445437d792e43906703fff75ca8ff43ccdb11f33f263"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.20.1"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
|
||||
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
|
||||
],
|
||||
"version": "==1.11.0"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39",
|
||||
"sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22"
|
||||
],
|
||||
"version": "==1.24.1"
|
||||
},
|
||||
"uwsgi": {
|
||||
"hashes": [
|
||||
"sha256:d2318235c74665a60021a4fc7770e9c2756f9fc07de7b8c22805efe85b5ab277"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.0.17.1"
|
||||
},
|
||||
"werkzeug": {
|
||||
"hashes": [
|
||||
"sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c",
|
||||
"sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b"
|
||||
],
|
||||
"version": "==0.14.1"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
|
@ -11,17 +11,17 @@ from .endpoints import (
|
|||
)
|
||||
from .config import get_config_location
|
||||
# Initialize the Flask application and the Flask Restful API
|
||||
login = Flask(__name__)
|
||||
login.config.from_object(get_config_location())
|
||||
login_api = Api(login, catch_all_404s=True)
|
||||
sso = Flask(__name__)
|
||||
sso.config.from_object(get_config_location())
|
||||
sso_api = Api(sso, catch_all_404s=True)
|
||||
|
||||
# Define the endpoints
|
||||
login_api.add_resource(AuthenticateAntisocialEndpoint, '/api/antisocial')
|
||||
login_api.add_resource(AuthorizeFacebookEndpoint, '/api/social/facebook')
|
||||
login_api.add_resource(AuthorizeGithubEndpoint, '/api/social/github')
|
||||
login_api.add_resource(AuthorizeGoogleEndpoint, '/api/social/google')
|
||||
login_api.add_resource(SocialLoginTokensEndpoint, '/api/social/tokens')
|
||||
login_api.add_resource(LogoutEndpoint, '/api/logout')
|
||||
sso_api.add_resource(AuthenticateAntisocialEndpoint, '/api/antisocial')
|
||||
sso_api.add_resource(AuthorizeFacebookEndpoint, '/api/social/facebook')
|
||||
sso_api.add_resource(AuthorizeGithubEndpoint, '/api/social/github')
|
||||
sso_api.add_resource(AuthorizeGoogleEndpoint, '/api/social/google')
|
||||
sso_api.add_resource(SocialLoginTokensEndpoint, '/api/social/tokens')
|
||||
sso_api.add_resource(LogoutEndpoint, '/api/logout')
|
||||
|
||||
|
||||
def add_cors_headers(response):
|
||||
|
@ -38,4 +38,4 @@ def add_cors_headers(response):
|
|||
return response
|
||||
|
||||
|
||||
login.after_request(add_cors_headers)
|
||||
sso.after_request(add_cors_headers)
|
|
@ -8,9 +8,9 @@ class LoginConfigException(Exception):
|
|||
class BaseConfig:
|
||||
"""Base configuration."""
|
||||
DEBUG = False
|
||||
LOGIN_BASE_URL = os.environ['LOGIN_BASE_URL']
|
||||
SECRET_KEY = os.environ['JWT_SECRET']
|
||||
SELENE_BASE_URL = os.environ['SELENE_BASE_URL']
|
||||
SERVICE_BASE_URL = os.environ['SERVICE_BASE_URL']
|
||||
SSO_BASE_URL = os.environ['SSO_BASE_URL']
|
||||
TARTARUS_BASE_URL = os.environ['TARTARUS_BASE_URL']
|
||||
|
||||
|
||||
|
@ -29,7 +29,7 @@ class ProdConfig(BaseConfig):
|
|||
|
||||
def get_config_location():
|
||||
environment_configs = dict(
|
||||
dev='login_api.config.DevelopmentConfig',
|
||||
dev=DevelopmentConfig,
|
||||
test=TestConfig,
|
||||
prod=ProdConfig
|
||||
)
|
|
@ -11,7 +11,7 @@ class AuthorizeFacebookEndpoint(SeleneEndpoint):
|
|||
'{tartarus_url}/social/auth/facebook'
|
||||
'?clientUri={login_url}&path=/social/login'.format(
|
||||
tartarus_url=self.config['TARTARUS_BASE_URL'],
|
||||
login_url=self.config['LOGIN_BASE_URL']
|
||||
login_url=self.config['SSO_BASE_URL']
|
||||
)
|
||||
)
|
||||
return redirect(tartarus_auth_endpoint)
|
|
@ -12,7 +12,7 @@ class AuthorizeGithubEndpoint(SeleneEndpoint):
|
|||
'{tartarus_url}/social/auth/github'
|
||||
'?clientUri={login_url}&path=/social/login'.format(
|
||||
tartarus_url=self.config['TARTARUS_BASE_URL'],
|
||||
login_url=self.config['LOGIN_BASE_URL']
|
||||
login_url=self.config['SSO_BASE_URL']
|
||||
)
|
||||
)
|
||||
return redirect(tartarus_auth_endpoint)
|
|
@ -11,7 +11,7 @@ class AuthorizeGoogleEndpoint(SeleneEndpoint):
|
|||
tartarus_auth_endpoint = (
|
||||
'{tartarus_url}/social/auth/google'
|
||||
'?clientUri={login_url}&path=/social/login'.format(
|
||||
login_url=self.config['LOGIN_BASE_URL'],
|
||||
login_url=self.config['SSO_BASE_URL'],
|
||||
tartarus_url=self.config['TARTARUS_BASE_URL']
|
||||
)
|
||||
)
|
|
@ -1,5 +1,5 @@
|
|||
[uwsgi]
|
||||
master = true
|
||||
module = login_api.api:login
|
||||
module = sso_api.api:sso
|
||||
processes = 4
|
||||
socket = :7102
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# The selene-shared parent image contains all the common Docker configs for
|
||||
# all Selene apps and services see the "shared" directory in this repository.
|
||||
FROM docker.mycroft.ai/selene-shared:latest
|
||||
FROM docker.mycroft.ai/selene-shared:2018.4
|
||||
LABEL description="Selene Skill Service API"
|
||||
|
||||
# Use pipenv to install the package's dependencies in the container
|
||||
|
@ -16,7 +16,7 @@ RUN rm Pipfile
|
|||
RUN rm Pipfile.lock
|
||||
|
||||
# Load the skill service application to the image
|
||||
COPY skill_service /opt/selene/skill_service
|
||||
COPY skill/skill_service /opt/selene/skill_service
|
||||
WORKDIR /opt/selene/
|
||||
|
||||
EXPOSE 7100
|
|
@ -9,8 +9,5 @@ mongoengine = "*"
|
|||
pygithub = "*"
|
||||
uwsgi = "*"
|
||||
|
||||
[dev-packages]
|
||||
selene-util = {path = "./../../../shared"}
|
||||
|
||||
[requires]
|
||||
python_version = "3.7"
|
|
@ -0,0 +1,234 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "0249828591e0b2cebfad9c9ff2d00f8e931f5228061b151f12666add5cbd2d81"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.7"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"aniso8601": {
|
||||
"hashes": [
|
||||
"sha256:547e7bc88c19742e519fb4ca39f4b8113fdfb8fca322e325f16a8bfc6cfc553c",
|
||||
"sha256:e7560de91bf00baa712b2550a2fdebf0188c5fce2fcd1162fbac75c19bb29c95"
|
||||
],
|
||||
"version": "==4.0.1"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:339dc09518b07e2fa7eda5450740925974815557727d6bd35d319c1524a04a4c",
|
||||
"sha256:6d58c986d22b038c8c0df30d639f23a3e6d172a05c3583e766f4c0b785c0986a"
|
||||
],
|
||||
"version": "==2018.10.15"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
|
||||
],
|
||||
"version": "==3.0.4"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
|
||||
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
|
||||
],
|
||||
"version": "==7.0"
|
||||
},
|
||||
"deprecated": {
|
||||
"hashes": [
|
||||
"sha256:8bfeba6e630abf42b5d111b68a05f7fe3d6de7004391b3cd614947594f87a4ff",
|
||||
"sha256:b784e0ca85a8c1e694d77e545c10827bd99772392e79d5f5442e761515a1246e"
|
||||
],
|
||||
"version": "==1.2.4"
|
||||
},
|
||||
"flask": {
|
||||
"hashes": [
|
||||
"sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48",
|
||||
"sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05"
|
||||
],
|
||||
"version": "==1.0.2"
|
||||
},
|
||||
"flask-restful": {
|
||||
"hashes": [
|
||||
"sha256:5795519501347e108c436b693ff9a4d7b373a3ac9069627d64e4001c05dd3407",
|
||||
"sha256:e2f1b8063de3944b94c7f8be5cee4d2161db0267c54c5b757d875295061776fa"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.3.6"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e",
|
||||
"sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16"
|
||||
],
|
||||
"version": "==2.7"
|
||||
},
|
||||
"itsdangerous": {
|
||||
"hashes": [
|
||||
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
|
||||
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
|
||||
],
|
||||
"version": "==1.1.0"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
|
||||
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
|
||||
],
|
||||
"version": "==2.10"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432",
|
||||
"sha256:130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b",
|
||||
"sha256:19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9",
|
||||
"sha256:1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af",
|
||||
"sha256:1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834",
|
||||
"sha256:1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd",
|
||||
"sha256:1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d",
|
||||
"sha256:31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7",
|
||||
"sha256:3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b",
|
||||
"sha256:4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3",
|
||||
"sha256:525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c",
|
||||
"sha256:52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2",
|
||||
"sha256:52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7",
|
||||
"sha256:5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36",
|
||||
"sha256:5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1",
|
||||
"sha256:5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e",
|
||||
"sha256:7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1",
|
||||
"sha256:83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c",
|
||||
"sha256:857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856",
|
||||
"sha256:98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550",
|
||||
"sha256:bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492",
|
||||
"sha256:d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672",
|
||||
"sha256:e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401",
|
||||
"sha256:edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6",
|
||||
"sha256:efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6",
|
||||
"sha256:f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c",
|
||||
"sha256:f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd",
|
||||
"sha256:fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1"
|
||||
],
|
||||
"version": "==1.1.0"
|
||||
},
|
||||
"mongoengine": {
|
||||
"hashes": [
|
||||
"sha256:1c375c8bbae89fc3df672c619a5835a2bd15148f9e8939f214a0b398cf12525f",
|
||||
"sha256:e8ed6d9d7f648205f4adcd773bb25ce626fdc6cd74b2959451e425441fb0e6d3"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.16.0"
|
||||
},
|
||||
"pygithub": {
|
||||
"hashes": [
|
||||
"sha256:70d90139f61a3d88417ff15eaca6150d0b3ba7ef0dc59589ea3719c3ce518ef6"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.43.3"
|
||||
},
|
||||
"pyjwt": {
|
||||
"hashes": [
|
||||
"sha256:30b1380ff43b55441283cc2b2676b755cca45693ae3097325dea01f3d110628c",
|
||||
"sha256:4ee413b357d53fd3fb44704577afac88e72e878716116270d722723d65b42176"
|
||||
],
|
||||
"version": "==1.6.4"
|
||||
},
|
||||
"pymongo": {
|
||||
"hashes": [
|
||||
"sha256:025f94fc1e1364f00e50badc88c47f98af20012f23317234e51a11333ef986e6",
|
||||
"sha256:02aa7fb282606331aefbc0586e2cf540e9dbe5e343493295e7f390936ad2738e",
|
||||
"sha256:057210e831573e932702cf332012ed39da78edf0f02d24a3f0b213264a87a397",
|
||||
"sha256:0d946b79c56187fe139276d4c8ed612a27a616966c8b9779d6b79e2053587c8b",
|
||||
"sha256:104790893b928d310aae8a955e0bdbaa442fb0ac0a33d1bbb0741c791a407778",
|
||||
"sha256:15527ef218d95a8717486106553b0d54ff2641e795b65668754e17ab9ca6e381",
|
||||
"sha256:1826527a0b032f6e20e7ac7f72d7c26dd476a5e5aa82c04aa1c7088a59fded7d",
|
||||
"sha256:22e3aa4ce1c3eebc7f70f9ca7fd4ce1ea33e8bdb7b61996806cd312f08f84a3a",
|
||||
"sha256:244e1101e9a48615b9a16cbd194f73c115fdfefc96894803158608115f703b26",
|
||||
"sha256:24b8c04fdb633a84829d03909752c385faef249c06114cc8d8e1700b95aae5c8",
|
||||
"sha256:2c276696350785d3104412cbe3ac70ab1e3a10c408e7b20599ee41403a3ed630",
|
||||
"sha256:2d8474dc833b1182b651b184ace997a7bd83de0f51244de988d3c30e49f07de3",
|
||||
"sha256:3119b57fe1d964781e91a53e81532c85ed1701baaddec592e22f6b77a9fdf3df",
|
||||
"sha256:3bee8e7e0709b0fcdaa498a3e513bde9ffc7cd09dbceb11e425bd91c89dbd5b6",
|
||||
"sha256:436c071e01a464753d30dbfc8768dd93aecf2a8e378e5314d130b95e77b4d612",
|
||||
"sha256:46635e3f19ad04d5a7d7cf23d232388ddbfccf46d9a3b7436b6abadda4e84813",
|
||||
"sha256:4772e0b679717e7ac4608d996f57b6f380748a919b457cb05bb941467b888b22",
|
||||
"sha256:4e2cd80e16f481a62c3175b607373200e714ed29025f21559ebf7524f295689f",
|
||||
"sha256:52732960efa0e003ca1c092dc0a3c65276e897681287a788a01ca78dda3b41f0",
|
||||
"sha256:55a7de51ec7d1731b2431886d0349146645f2816e5b8eb982d7c49f89472c9f3",
|
||||
"sha256:5f8ed5934197a2d4b2087646e98de3e099a237099dcf498b9e38dd3465f74ef4",
|
||||
"sha256:64b064124fcbc8eb04a155117dc4d9a336e3cda3f069958fbc44fe70c3c3d1e9",
|
||||
"sha256:65958b8e4319f992e85dad59d8081888b97fcdbde5f0d14bc28f2848b92d3ef1",
|
||||
"sha256:7683428862e20c6a790c19e64f8ccf487f613fbc83d47e3d532df9c81668d451",
|
||||
"sha256:78566d5570c75a127c2491e343dc006798a384f06be588fe9b0cbe5595711559",
|
||||
"sha256:7d1cb00c093dbf1d0b16ccf123e79dee3b82608e4a2a88947695f0460eef13ff",
|
||||
"sha256:8c74e2a9b594f7962c62cef7680a4cb92a96b4e6e3c2f970790da67cc0213a7e",
|
||||
"sha256:8e60aa7699170f55f4b0f56ee6f8415229777ac7e4b4b1aa41fc61eec08c1f1d",
|
||||
"sha256:9447b561529576d89d3bf973e5241a88cf76e45bd101963f5236888713dea774",
|
||||
"sha256:970055bfeb0be373f2f5299a3db8432444bad3bc2f198753ee6c2a3a781e0959",
|
||||
"sha256:a6344b8542e584e140dc3c651d68bde51270e79490aa9320f9e708f9b2c39bd5",
|
||||
"sha256:ce309ca470d747b02ba6069d286a17b7df8e9c94d10d727d9cf3a64e51d85184",
|
||||
"sha256:cfbd86ed4c2b2ac71bbdbcea6669bf295def7152e3722ddd9dda94ac7981f33d",
|
||||
"sha256:d7929c513732dff093481f4a0954ed5ff16816365842136b17caa0b4992e49d3"
|
||||
],
|
||||
"version": "==3.7.2"
|
||||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
"sha256:31cb35c89bd7d333cd32c5f278fca91b523b0834369e757f4c5641ea252236ca",
|
||||
"sha256:8e0f8568c118d3077b46be7d654cc8167fa916092e28320cde048e54bfc9f1e6"
|
||||
],
|
||||
"version": "==2018.7"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:65b3a120e4329e33c9889db89c80976c5272f56ea92d3e74da8a463992e3ff54",
|
||||
"sha256:ea881206e59f41dbd0bd445437d792e43906703fff75ca8ff43ccdb11f33f263"
|
||||
],
|
||||
"version": "==2.20.1"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
|
||||
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
|
||||
],
|
||||
"version": "==1.11.0"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39",
|
||||
"sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22"
|
||||
],
|
||||
"version": "==1.24.1"
|
||||
},
|
||||
"uwsgi": {
|
||||
"hashes": [
|
||||
"sha256:d2318235c74665a60021a4fc7770e9c2756f9fc07de7b8c22805efe85b5ab277"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.0.17.1"
|
||||
},
|
||||
"werkzeug": {
|
||||
"hashes": [
|
||||
"sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c",
|
||||
"sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b"
|
||||
],
|
||||
"version": "==0.14.1"
|
||||
},
|
||||
"wrapt": {
|
||||
"hashes": [
|
||||
"sha256:d4d560d479f2c21e1b5443bbd15fe7ec4b37fe7e53d335d3b9b0a7b1226fe3c6"
|
||||
],
|
||||
"version": "==1.10.11"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
from flask import Flask
|
||||
from flask_restful import Api
|
||||
|
||||
from skill_service.api.endpoints import AllSkillsEndpoint, SkillDetailEndpoint
|
||||
from .endpoints import AllSkillsEndpoint, SkillDetailEndpoint
|
||||
# from .config import get_config_location
|
||||
|
||||
|
|
@ -9,10 +9,6 @@ LABEL maintainer="Mycroft AI <devops@mycroft.ai>"
|
|||
# Install the software required for this image
|
||||
RUN pip install pipenv
|
||||
|
||||
# Copy the applicaction code to the image
|
||||
COPY selene_util /opt/selene/selene_util
|
||||
WORKDIR /opt/selene/
|
||||
|
||||
# Use pipenv to install the dependencies for selene-util
|
||||
COPY Pipfile Pipfile
|
||||
COPY Pipfile.lock Pipfile.lock
|
||||
|
@ -22,5 +18,9 @@ RUN pipenv install --system
|
|||
# the Pipfile can be removed from the container. This makes way for the
|
||||
# pepenv to use these files to install dependencies for the Selene services
|
||||
# or applications that will use this Docker config
|
||||
RUN rm /opt/selene/Pipfile
|
||||
RUN rm /opt/selene/Pipfile.lock
|
||||
RUN rm Pipfile
|
||||
RUN rm Pipfile.lock
|
||||
|
||||
# Copy the applicaction code to the image
|
||||
COPY selene_util /opt/selene/selene_util
|
||||
WORKDIR /opt/selene/
|
|
@ -0,0 +1,2 @@
|
|||
dist
|
||||
node_modules
|
|
@ -0,0 +1,13 @@
|
|||
# Editor configuration, see http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
|
@ -0,0 +1,39 @@
|
|||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
|
@ -7,8 +7,10 @@ COPY package*.json ./
|
|||
RUN npm install
|
||||
COPY . .
|
||||
ARG selene_env
|
||||
RUN npm run build-${selene_env}
|
||||
ARG application_name
|
||||
RUN npm run build -- --project=globalnav
|
||||
RUN npm run build-${selene_env} -- --project=${application_name}
|
||||
|
||||
# STAGE TWO: build the web server and copy the compiled angular app to it.
|
||||
FROM nginx:latest
|
||||
COPY --from=build /usr/src/app/dist/mycroft-marketplace /usr/share/nginx/html
|
||||
COPY --from=build /usr/src/app/dist/${application_name} /usr/share/nginx/html
|
|
@ -0,0 +1,27 @@
|
|||
# Internet
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.0.3.
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
|
@ -0,0 +1,506 @@
|
|||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"internet": {
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"projectType": "application",
|
||||
"prefix": "app",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"styleext": "scss"
|
||||
}
|
||||
},
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/internet",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "src/tsconfig.app.json",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"extractCss": true,
|
||||
"namedChunks": false,
|
||||
"aot": true,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "5mb"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "internet:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "internet:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "internet:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "src/test.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "src/tsconfig.spec.json",
|
||||
"karmaConfig": "src/karma.conf.js",
|
||||
"styles": [
|
||||
"src/styles.scss"
|
||||
],
|
||||
"scripts": [],
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
]
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"src/tsconfig.app.json",
|
||||
"src/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"internet-e2e": {
|
||||
"root": "e2e/",
|
||||
"projectType": "application",
|
||||
"prefix": "",
|
||||
"architect": {
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "e2e/protractor.conf.js",
|
||||
"devServerTarget": "internet:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"devServerTarget": "internet:serve:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": "e2e/tsconfig.e2e.json",
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"market": {
|
||||
"root": "projects/market/",
|
||||
"sourceRoot": "projects/market/src",
|
||||
"projectType": "application",
|
||||
"prefix": "market",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"styleext": "scss",
|
||||
"spec": false
|
||||
},
|
||||
"@schematics/angular:class": {
|
||||
"spec": false
|
||||
},
|
||||
"@schematics/angular:directive": {
|
||||
"spec": false
|
||||
},
|
||||
"@schematics/angular:guard": {
|
||||
"spec": false
|
||||
},
|
||||
"@schematics/angular:module": {
|
||||
"spec": false
|
||||
},
|
||||
"@schematics/angular:pipe": {
|
||||
"spec": false
|
||||
},
|
||||
"@schematics/angular:service": {
|
||||
"spec": false
|
||||
}
|
||||
},
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/market",
|
||||
"index": "projects/market/src/index.html",
|
||||
"main": "projects/market/src/main.ts",
|
||||
"polyfills": "projects/market/src/polyfills.ts",
|
||||
"tsConfig": "projects/market/tsconfig.app.json",
|
||||
"assets": [
|
||||
"projects/market/src/favicon.ico",
|
||||
"projects/market/src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"projects/market/src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "projects/market/src/environments/environment.ts",
|
||||
"with": "projects/market/src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"extractCss": true,
|
||||
"namedChunks": false,
|
||||
"aot": true,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "5mb"
|
||||
}
|
||||
]
|
||||
},
|
||||
"test": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "projects/market/src/environments/environment.ts",
|
||||
"with": "projects/market/src/environments/environment.test.ts"
|
||||
}
|
||||
]
|
||||
},
|
||||
"development": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "projects/market/src/environments/environment.ts",
|
||||
"with": "projects/market/src/environments/environment.dev.ts"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "market:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "market:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "market:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "projects/market/src/test.ts",
|
||||
"polyfills": "projects/market/src/polyfills.ts",
|
||||
"tsConfig": "projects/market/tsconfig.spec.json",
|
||||
"karmaConfig": "projects/market/karma.conf.js",
|
||||
"styles": [
|
||||
"projects/market/src/styles.scss"
|
||||
],
|
||||
"scripts": [],
|
||||
"assets": [
|
||||
"projects/market/src/favicon.ico",
|
||||
"projects/market/src/assets"
|
||||
]
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"projects/market/tsconfig.app.json",
|
||||
"projects/market/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"market-e2e": {
|
||||
"root": "projects/market-e2e/",
|
||||
"projectType": "application",
|
||||
"prefix": "",
|
||||
"architect": {
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "projects/market-e2e/protractor.conf.js",
|
||||
"devServerTarget": "market:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"devServerTarget": "market:serve:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": "projects/market-e2e/tsconfig.e2e.json",
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sso": {
|
||||
"root": "projects/sso/",
|
||||
"sourceRoot": "projects/sso/src",
|
||||
"projectType": "application",
|
||||
"prefix": "sso",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"styleext": "scss",
|
||||
"spec": false
|
||||
},
|
||||
"@schematics/angular:class": {
|
||||
"spec": false
|
||||
},
|
||||
"@schematics/angular:directive": {
|
||||
"spec": false
|
||||
},
|
||||
"@schematics/angular:guard": {
|
||||
"spec": false
|
||||
},
|
||||
"@schematics/angular:module": {
|
||||
"spec": false
|
||||
},
|
||||
"@schematics/angular:pipe": {
|
||||
"spec": false
|
||||
},
|
||||
"@schematics/angular:service": {
|
||||
"spec": false
|
||||
}
|
||||
},
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/sso",
|
||||
"index": "projects/sso/src/index.html",
|
||||
"main": "projects/sso/src/main.ts",
|
||||
"polyfills": "projects/sso/src/polyfills.ts",
|
||||
"tsConfig": "projects/sso/tsconfig.app.json",
|
||||
"assets": [
|
||||
"projects/sso/src/favicon.ico",
|
||||
"projects/sso/src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"projects/sso/src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "projects/sso/src/environments/environment.ts",
|
||||
"with": "projects/sso/src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"extractCss": true,
|
||||
"namedChunks": false,
|
||||
"aot": true,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "5mb"
|
||||
}
|
||||
]
|
||||
},
|
||||
"test": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "projects/market/src/environments/environment.ts",
|
||||
"with": "projects/market/src/environments/environment.test.ts"
|
||||
}
|
||||
]
|
||||
},
|
||||
"development": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "projects/market/src/environments/environment.ts",
|
||||
"with": "projects/market/src/environments/environment.dev.ts"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "sso:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "sso:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "sso:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "projects/sso/src/test.ts",
|
||||
"polyfills": "projects/sso/src/polyfills.ts",
|
||||
"tsConfig": "projects/sso/tsconfig.spec.json",
|
||||
"karmaConfig": "projects/sso/karma.conf.js",
|
||||
"styles": [
|
||||
"projects/sso/src/styles.scss"
|
||||
],
|
||||
"scripts": [],
|
||||
"assets": [
|
||||
"projects/sso/src/favicon.ico",
|
||||
"projects/sso/src/assets"
|
||||
]
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"projects/sso/tsconfig.app.json",
|
||||
"projects/sso/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sso-e2e": {
|
||||
"root": "projects/sso-e2e/",
|
||||
"projectType": "application",
|
||||
"prefix": "",
|
||||
"architect": {
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "projects/sso-e2e/protractor.conf.js",
|
||||
"devServerTarget": "sso:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"devServerTarget": "sso:serve:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": "projects/sso-e2e/tsconfig.e2e.json",
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"globalnav": {
|
||||
"root": "projects/globalnav",
|
||||
"sourceRoot": "projects/globalnav/src",
|
||||
"projectType": "library",
|
||||
"prefix": "globalnav",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"options": {
|
||||
"tsConfig": "projects/globalnav/tsconfig.lib.json",
|
||||
"project": "projects/globalnav/ng-package.json"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "projects/globalnav/src/test.ts",
|
||||
"tsConfig": "projects/globalnav/tsconfig.spec.json",
|
||||
"karmaConfig": "projects/globalnav/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"projects/globalnav/tsconfig.lib.json",
|
||||
"projects/globalnav/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "internet"
|
||||
}
|
|
@ -9,6 +9,6 @@ describe('workspace-project App', () => {
|
|||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getParagraphText()).toEqual('Welcome to frontend!');
|
||||
expect(page.getParagraphText()).toEqual('Welcome to internet!');
|
||||
});
|
||||
});
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"name": "internet",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"build-dev": "ng build --configuration=development",
|
||||
"build-test": "ng build --configuration=test",
|
||||
"build-prod": "ng build --prod",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~7.0.0",
|
||||
"@angular/cdk": "^7.0.1",
|
||||
"@angular/common": "~7.0.0",
|
||||
"@angular/compiler": "~7.0.0",
|
||||
"@angular/core": "~7.0.0",
|
||||
"@angular/flex-layout": "^7.0.0-beta.19",
|
||||
"@angular/forms": "~7.0.0",
|
||||
"@angular/http": "~7.0.0",
|
||||
"@angular/material": "^7.0.1",
|
||||
"@angular/platform-browser": "~7.0.0",
|
||||
"@angular/platform-browser-dynamic": "~7.0.0",
|
||||
"@angular/router": "~7.0.0",
|
||||
"@fortawesome/angular-fontawesome": "^0.3.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.7",
|
||||
"@fortawesome/free-brands-svg-icons": "^5.4.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.4.2",
|
||||
"angular-font-awesome": "^3.1.2",
|
||||
"core-js": "^2.5.4",
|
||||
"font-awesome": "^4.7.0",
|
||||
"rxjs": "~6.3.3",
|
||||
"zone.js": "~0.8.26"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.10.0",
|
||||
"@angular-devkit/build-ng-packagr": "~0.10.0",
|
||||
"@angular/cli": "~7.0.3",
|
||||
"@angular/compiler-cli": "~7.0.0",
|
||||
"@angular/language-service": "~7.0.0",
|
||||
"@types/node": "~8.9.4",
|
||||
"@types/jasmine": "~2.8.8",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"codelyzer": "~4.5.0",
|
||||
"jasmine-core": "~2.99.1",
|
||||
"jasmine-spec-reporter": "~4.2.1",
|
||||
"karma": "~3.0.0",
|
||||
"karma-chrome-launcher": "~2.2.0",
|
||||
"karma-coverage-istanbul-reporter": "~2.0.1",
|
||||
"karma-jasmine": "~1.1.2",
|
||||
"karma-jasmine-html-reporter": "^0.2.2",
|
||||
"ng-packagr": "^4.2.0",
|
||||
"protractor": "~5.4.0",
|
||||
"ts-node": "~7.0.0",
|
||||
"tsickle": ">=0.29.0",
|
||||
"tslib": "^1.9.0",
|
||||
"tslint": "~5.11.0",
|
||||
"typescript": "~3.1.1"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, '../../coverage'),
|
||||
reports: ['html', 'lcovonly'],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
};
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../dist/globalnav",
|
||||
"lib": {
|
||||
"entryFile": "src/public_api.ts",
|
||||
"cssUrl": "inline",
|
||||
"umdModuleIds": {
|
||||
"@fortawesome/angular-fontawesome": "angularFontawesome",
|
||||
"@fortawesome/free-brands-svg-icons": "freeBrandsSvgIcons",
|
||||
"@fortawesome/free-solid-svg-icons": "freeSolidSvgIcons"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "globalnav",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^7.0.0",
|
||||
"@angular/core": "^7.0.0",
|
||||
"@angular/flex-layout": "^7.0.0-beta.19"
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<div fxFlex="nogrow" class="nav-footer">
|
||||
<mat-divider></mat-divider>
|
||||
<div fxLayout="row wrap" fxLayoutAlign="start" class="social-icons">
|
||||
<button
|
||||
*ngFor="let media of socialMediaIcons"
|
||||
mat-icon-button
|
||||
class="social-icon-button"
|
||||
(click)="navigateToSocialMedia(media.url)"
|
||||
>
|
||||
<fa-icon [icon]="media.icon"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button mat-flat-button (click)="navigateToContactUs()" class="footer-text">Contact Us</button>
|
||||
</div>
|
||||
<div>
|
||||
<button mat-flat-button (click)="navigateToMediaKit()" class="footer-text">Media Kit</button>
|
||||
</div>
|
||||
<div>
|
||||
<button mat-flat-button (click)="navigateToTermsOfUse()" class="footer-text">Terms of Use</button>
|
||||
</div>
|
||||
<div>
|
||||
<button mat-flat-button (click)="navigateToPrivacyPolicy()" class="footer-text">Privacy Policy</button>
|
||||
</div>
|
||||
<div class="mat-body-2">© Mycroft AI, Inc.</div>
|
||||
</div>
|
|
@ -0,0 +1,30 @@
|
|||
.nav-footer {
|
||||
//bottom: 0;
|
||||
padding: 16px;
|
||||
//position: fixed;
|
||||
}
|
||||
|
||||
.social-icons {
|
||||
width: 180px;
|
||||
margin-left: -10px;
|
||||
}
|
||||
|
||||
.social-icon-button {
|
||||
color: #6c7a89;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.footer-text {
|
||||
color: #6c7a89;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mat-body-2 {
|
||||
color: #6c7a89;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.mat-divider.mat-divider-vertical {
|
||||
height: 30px;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
|
||||
import {
|
||||
faFacebook,
|
||||
faInstagram,
|
||||
faLinkedin,
|
||||
faMedium,
|
||||
faReddit,
|
||||
faTelegram,
|
||||
faTwitter,
|
||||
faYoutube,
|
||||
} from '@fortawesome/free-brands-svg-icons';
|
||||
|
||||
@Component({
|
||||
selector: 'globalnav-footer',
|
||||
templateUrl: './footer.component.html',
|
||||
styleUrls: ['./footer.component.scss']
|
||||
})
|
||||
export class FooterComponent implements OnInit {
|
||||
@Input() contactUsUrl: string;
|
||||
@Input() mediaKitUrl: string;
|
||||
@Input() privacyPolicyUrl: string;
|
||||
public socialMediaIcons = [
|
||||
{icon: faTwitter, url: 'https://twitter.com/mycroft_ai'},
|
||||
{icon: faFacebook, url: 'https://www.facebook.com/aiforeveryone/'},
|
||||
{icon: faInstagram, url: 'https://www.instagram.com/mycroft_ai/'},
|
||||
{icon: faYoutube, url: 'https://www.youtube.com/channel/UC1dlmB1lup9RwFQBSGnhA-g'},
|
||||
{icon: faTelegram, url: 'https://t.me/mycroft_ai'},
|
||||
{icon: faReddit, url: 'https://www.reddit.com/r/Mycroftai/'},
|
||||
{icon: faLinkedin, url: 'https://www.linkedin.com/company/mycroft-a.i./'},
|
||||
{icon: faMedium, url: 'https://medium.com/@mycroftai'}
|
||||
];
|
||||
@Input() termsOfUseUrl: string;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
navigateToSocialMedia(url) {
|
||||
window.location.assign(url);
|
||||
}
|
||||
|
||||
navigateToTermsOfUse() {
|
||||
window.location.assign(this.termsOfUseUrl);
|
||||
}
|
||||
|
||||
navigateToPrivacyPolicy() {
|
||||
window.location.assign(this.privacyPolicyUrl);
|
||||
}
|
||||
|
||||
navigateToContactUs() {
|
||||
window.location.assign(this.contactUsUrl);
|
||||
}
|
||||
|
||||
navigateToMediaKit() {
|
||||
window.location.assign(this.mediaKitUrl);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
<div class="app">
|
||||
<mat-toolbar color="primary">
|
||||
<button mat-icon-button (click)="snav.toggle()">
|
||||
<fa-icon [icon]="menuIcon"></fa-icon>
|
||||
</button>
|
||||
<a href="{{environment.wordpressUrl}}">
|
||||
<div class="globalnav-logo"></div>
|
||||
</a>
|
||||
</mat-toolbar>
|
||||
|
||||
<mat-sidenav-container>
|
||||
<mat-sidenav
|
||||
#snav
|
||||
[mode]="mobileQuery.matches ? 'over' : 'side'"
|
||||
[opened]="!mobileQuery.matches"
|
||||
[fixedInViewport]="true"
|
||||
>
|
||||
<div fxFill fxLayout="column">
|
||||
<div fxFlex="initial">
|
||||
<a href="{{environment.wordpressUrl}}">
|
||||
<div class="globalnav-logo"></div>
|
||||
</a>
|
||||
<mat-divider></mat-divider>
|
||||
</div>
|
||||
<div fxFlex>
|
||||
<mat-nav-list [disableRipple]="true">
|
||||
<globalnav-primary-nav-item
|
||||
*ngFor="let nav of navigationItems"
|
||||
[primaryNavItem]="nav"
|
||||
>
|
||||
</globalnav-primary-nav-item>
|
||||
</mat-nav-list>
|
||||
</div>
|
||||
<globalnav-footer
|
||||
[contactUsUrl]="contactUsUrl"
|
||||
[mediaKitUrl]="mediaKitUrl"
|
||||
[privacyPolicyUrl]="privacyPolicyUrl"
|
||||
[termsOfUseUrl]="termsOfUseUrl"
|
||||
>
|
||||
</globalnav-footer>
|
||||
</div>
|
||||
</mat-sidenav>
|
||||
<mat-sidenav-content>
|
||||
<ng-content select="[appBody]"></ng-content>
|
||||
</mat-sidenav-content>
|
||||
</mat-sidenav-container>
|
||||
</div>
|
|
@ -0,0 +1,49 @@
|
|||
.app-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
// Use inline css to display the logo at top of sidebar because Angular
|
||||
// libraries do not support static assets yet.
|
||||
mat-toolbar {
|
||||
height: 50px;
|
||||
position: fixed;
|
||||
z-index: 2;
|
||||
button {
|
||||
margin-right: 20px;
|
||||
fa-icon {
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
.globalnav-logo {
|
||||
background: url("toolbar-logo.svg") no-repeat;
|
||||
height: 25px;
|
||||
margin-top: -5px;
|
||||
width: 168px;
|
||||
}
|
||||
}
|
||||
|
||||
mat-sidenav-container {
|
||||
mat-sidenav {
|
||||
border: none;
|
||||
margin-top: 50px;
|
||||
mat-divider {
|
||||
width: 200px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
mat-nav-list {
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
mat-sidenav-content {
|
||||
margin-top: 50px;
|
||||
background-color: #f1f3f4;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { MediaMatcher } from '@angular/cdk/layout';
|
||||
import { PrimaryNavItem } from './globalnav.service';
|
||||
import {
|
||||
faBars,
|
||||
faLightbulb,
|
||||
faRobot,
|
||||
faRocket,
|
||||
faRss,
|
||||
faStore,
|
||||
faUserCircle,
|
||||
faUsers
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
@Component({
|
||||
selector: 'globalnav-sidenav',
|
||||
templateUrl: './globalnav.component.html',
|
||||
styleUrls: ['./globalnav.component.scss']
|
||||
})
|
||||
|
||||
export class GlobalnavComponent implements OnInit {
|
||||
@Input() environment: any;
|
||||
public contactUsUrl: string;
|
||||
public isLoggedIn: boolean;
|
||||
public mediaKitUrl: string;
|
||||
public menuIcon = faBars;
|
||||
public mobileQuery: MediaQueryList;
|
||||
public navigationItems: PrimaryNavItem[];
|
||||
public privacyPolicyUrl: string;
|
||||
public termsOfUseUrl: string;
|
||||
|
||||
constructor(media: MediaMatcher) {
|
||||
this.mobileQuery = media.matchMedia('(max-width: 600px)');
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.buildNavigationItems();
|
||||
this.setLoginStatus();
|
||||
this.buildAccountNav();
|
||||
}
|
||||
|
||||
buildNavigationItems(): void {
|
||||
const aboutMycroftNav: PrimaryNavItem = {
|
||||
children: [
|
||||
{text: 'Team', url: this.environment.wordpressUrl + '/team'},
|
||||
{text: 'Careers', url: this.environment.wordpressUrl + '/careers'}
|
||||
],
|
||||
icon: faRobot,
|
||||
text: 'About Mycroft'
|
||||
};
|
||||
const blogNav: PrimaryNavItem = {
|
||||
icon: faRss,
|
||||
text: 'Blog',
|
||||
url: this.environment.wordpressUrl + '/blog'
|
||||
};
|
||||
const communityNav: PrimaryNavItem = {
|
||||
children: [
|
||||
{text: 'Chat', url: this.environment.chatUrl},
|
||||
{text: 'Forum', url: this.environment.forumUrl}
|
||||
],
|
||||
icon: faUsers,
|
||||
text: 'Community'
|
||||
};
|
||||
const contributeNav: PrimaryNavItem = {
|
||||
children: [
|
||||
{text: 'GitHub', url: 'https://github.com/MycroftAI'},
|
||||
{text: 'Translate', url: this.environment.translateUrl},
|
||||
{text: 'Wake Words', url: this.environment.accountUrl + '/#/precise'},
|
||||
{text: 'Text to Speech', url: this.environment.accountUrl + '/#/deepspeech'}
|
||||
],
|
||||
icon: faLightbulb,
|
||||
text: 'Contribute'
|
||||
};
|
||||
const getStartedNav: PrimaryNavItem = {
|
||||
children: [
|
||||
{text: 'Get Mycroft', url: this.environment.wordpressUrl + '/download'},
|
||||
{text: 'Documentation', url: this.environment.wordpressUrl + '/documentation'}
|
||||
],
|
||||
icon: faRocket,
|
||||
text: 'Get Started'
|
||||
};
|
||||
const marketplaceNav: PrimaryNavItem = {
|
||||
children: [
|
||||
{text: 'Skills', url: this.environment.marketplaceUrl + '/skills'},
|
||||
{text: 'Hardware', url: this.environment.wordpressUrl + '/shop'}
|
||||
],
|
||||
icon: faStore,
|
||||
text: 'Marketplace'
|
||||
};
|
||||
|
||||
this.navigationItems = [
|
||||
aboutMycroftNav,
|
||||
getStartedNav,
|
||||
blogNav,
|
||||
communityNav,
|
||||
contributeNav,
|
||||
marketplaceNav,
|
||||
];
|
||||
this.contactUsUrl = this.environment.wordpressUrl + '/contact';
|
||||
this.mediaKitUrl = this.environment.wordpressUrl + '/media';
|
||||
this.privacyPolicyUrl = this.environment.accountUrl + '/#/privacy-policy';
|
||||
this.termsOfUseUrl = this.environment.accountUrl + '/#/terms-of-use';
|
||||
}
|
||||
|
||||
setLoginStatus(): void {
|
||||
const cookies = document.cookie;
|
||||
const seleneTokenExists = cookies.includes('seleneToken');
|
||||
const seleneTokenEmpty = cookies.includes('seleneToken=""');
|
||||
this.isLoggedIn = seleneTokenExists && !seleneTokenEmpty;
|
||||
}
|
||||
|
||||
buildAccountNav() {
|
||||
const accountNav: PrimaryNavItem = {
|
||||
icon: faUserCircle,
|
||||
text: 'My Account'
|
||||
};
|
||||
if (this.isLoggedIn) {
|
||||
accountNav.children = [
|
||||
{text: 'Devices', url: this.environment.accountUrl + '/#/device'},
|
||||
{text: 'Profile', url: this.environment.accountUrl + '/#/profile'},
|
||||
{text: 'Skill Settings', url: this.environment.accountUrl + '/#/skill'},
|
||||
{text: 'Subscription', url: this.environment.accountUrl + '/#/account'},
|
||||
{text: 'User Settings', url: this.environment.accountUrl + '/#/setting/basic'},
|
||||
{text: 'Logout', url: this.environment.singleSignOnUrl + '/logout?redirect=' + window.location.href}
|
||||
];
|
||||
} else {
|
||||
accountNav.children = [
|
||||
{text: 'Log In', url: this.environment.singleSignOnUrl + '/login?redirect=' + window.location.href},
|
||||
{text: 'Sign Up', url: this.environment.singleSignOnUrl + '/signup'}
|
||||
];
|
||||
}
|
||||
this.navigationItems.push(accountNav);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatExpansionModule } from '@angular/material/expansion';
|
||||
import { MatListModule } from '@angular/material';
|
||||
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
|
||||
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||
|
||||
import { GlobalnavComponent } from './globalnav.component';
|
||||
import { GlobalnavService } from './globalnav.service';
|
||||
import { NavItemComponent } from './nav-item/nav-item.component';
|
||||
import { PrimaryNavItemComponent } from './primary-nav-item/primary-nav-item.component';
|
||||
import { FooterComponent } from './footer/footer.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FlexLayoutModule,
|
||||
FontAwesomeModule,
|
||||
MatButtonModule,
|
||||
MatDividerModule,
|
||||
MatExpansionModule,
|
||||
MatListModule,
|
||||
MatSidenavModule,
|
||||
MatToolbarModule,
|
||||
],
|
||||
declarations: [
|
||||
GlobalnavComponent,
|
||||
NavItemComponent,
|
||||
PrimaryNavItemComponent,
|
||||
FooterComponent
|
||||
],
|
||||
exports: [
|
||||
GlobalnavComponent
|
||||
],
|
||||
providers: [
|
||||
GlobalnavService
|
||||
]
|
||||
})
|
||||
export class GlobalnavModule { }
|
|
@ -0,0 +1,25 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { IconDefinition } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
export interface NavItem {
|
||||
text: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface PrimaryNavItem {
|
||||
children?: NavItem[];
|
||||
icon: IconDefinition;
|
||||
text: string;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class GlobalnavService {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<mat-list-item (click)="navigateToUrl()">
|
||||
<div style="width: 40px"></div>
|
||||
<span class="mat-body-1" [ngStyle]="navItemStyle">{{item.text}}</span>
|
||||
</mat-list-item>
|
|
@ -0,0 +1,8 @@
|
|||
.mat-list-item {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.mat-body-1 {
|
||||
color: #6c7a89;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
|
||||
import { NavItem } from '../globalnav.service';
|
||||
|
||||
@Component({
|
||||
selector: 'globalnav-nav-item',
|
||||
templateUrl: './nav-item.component.html',
|
||||
styleUrls: ['./nav-item.component.scss']
|
||||
})
|
||||
export class NavItemComponent implements OnInit {
|
||||
@Input() item: NavItem;
|
||||
public navItemStyle: object;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.buildNavItemStyle();
|
||||
}
|
||||
|
||||
buildNavItemStyle() {
|
||||
if (window.location.href.includes(this.item.url)) {
|
||||
this.navItemStyle = {'color': '#22a7f0'};
|
||||
}
|
||||
}
|
||||
navigateToUrl() {
|
||||
window.location.assign(this.item.url);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<mat-list-item (click)="onItemSelected()" class="nav-item">
|
||||
<div fxLayout="row" style="width: 100%;">
|
||||
<!-- Not all of the icons are the same width so center them -->
|
||||
<span style="text-align: center; width: 20px; margin-right: 20px">
|
||||
<fa-icon [icon]="primaryNavItem.icon" style="color: #22a7f0"></fa-icon>
|
||||
</span>
|
||||
<span>
|
||||
{{primaryNavItem.text}}
|
||||
</span>
|
||||
</div>
|
||||
</mat-list-item>
|
||||
<div *ngIf="expanded">
|
||||
<globalnav-nav-item
|
||||
*ngFor="let child of primaryNavItem.children"
|
||||
[item]="child"
|
||||
>
|
||||
</globalnav-nav-item>
|
||||
</div>
|
|
@ -0,0 +1,7 @@
|
|||
.nav-item {
|
||||
color: #2c3e50;
|
||||
height: 30px;
|
||||
}
|
||||
.nav-item:hover {
|
||||
background-color: #e4f1fe;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
|
||||
import { PrimaryNavItem } from '../globalnav.service';
|
||||
|
||||
@Component({
|
||||
selector: 'globalnav-primary-nav-item',
|
||||
templateUrl: './primary-nav-item.component.html',
|
||||
styleUrls: ['./primary-nav-item.component.scss']
|
||||
})
|
||||
export class PrimaryNavItemComponent implements OnInit {
|
||||
public expanded = false;
|
||||
@Input() primaryNavItem: PrimaryNavItem;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
this.expandCurrentLocation();
|
||||
}
|
||||
|
||||
expandCurrentLocation() {
|
||||
if (this.primaryNavItem.children && this.primaryNavItem.children.length) {
|
||||
this.primaryNavItem.children.forEach(
|
||||
(navItem) => {
|
||||
if (window.location.href.includes(navItem.url)) {
|
||||
this.expanded = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
onItemSelected() {
|
||||
if (this.primaryNavItem.children && this.primaryNavItem.children.length) {
|
||||
this.expanded = !this.expanded;
|
||||
} else {
|
||||
window.location.assign(this.primaryNavItem.url);
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Public API Surface of globalnav
|
||||
*/
|
||||
|
||||
export * from './lib/globalnav.service';
|
||||
export * from './lib/globalnav.component';
|
||||
export * from './lib/globalnav.module';
|
|
@ -0,0 +1,22 @@
|
|||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'core-js/es7/reflect';
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import {
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: any;
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
);
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"module": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"inlineSources": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"importHelpers": true,
|
||||
"types": [],
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2018"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"annotateForClosureCompiler": true,
|
||||
"skipTemplateCodegen": true,
|
||||
"strictMetadataEmit": true,
|
||||
"fullTemplateTypeCheck": true,
|
||||
"strictInjectionParameters": true,
|
||||
"enableResourceInlining": true
|
||||
},
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
|
@ -1,16 +1,14 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/spec",
|
||||
"module": "commonjs",
|
||||
"outDir": "../../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"test.ts",
|
||||
"polyfills.ts"
|
||||
"src/test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../tslint.json",
|
||||
"rules": {
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"globalnav",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"globalnav",
|
||||
"kebab-case"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -9,6 +9,6 @@ describe('workspace-project App', () => {
|
|||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getParagraphText()).toEqual('Welcome to mycroft-marketplace!');
|
||||
expect(page.getParagraphText()).toEqual('Welcome to market!');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,11 @@
|
|||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
navigateTo() {
|
||||
return browser.get('/');
|
||||
}
|
||||
|
||||
getParagraphText() {
|
||||
return element(by.css('market-root h1')).getText();
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"outDir": "../../out-tsc/app",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
|
@ -1,9 +1,11 @@
|
|||
# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
# For IE 9-11 support, please uncomment the last line of the file and adjust as needed
|
||||
#
|
||||
# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed
|
||||
|
||||
> 0.5%
|
||||
last 2 versions
|
||||
Firefox ESR
|
||||
not dead
|
||||
# IE 9-11
|
||||
not IE 9-11
|
|
@ -16,7 +16,7 @@ module.exports = function (config) {
|
|||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, '../coverage'),
|
||||
dir: require('path').join(__dirname, '../../coverage'),
|
||||
reports: ['html', 'lcovonly'],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
|
@ -1,7 +1,7 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { PageNotFoundComponent } from "./page-not-found/page-not-found.component";
|
||||
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: '/skills', pathMatch: 'full' },
|
|
@ -0,0 +1,9 @@
|
|||
<globalnav-sidenav [environment]="environment">
|
||||
<!--
|
||||
Inject the marketplace app into the <mat-sidenav-content> component
|
||||
of the global navigation menu library.
|
||||
-->
|
||||
<div appBody class="app-body">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</globalnav-sidenav>
|
|
@ -5,3 +5,8 @@
|
|||
margin-right: 3vw;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 20px;
|
||||
margin-top: -7px;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue