This commit is contained in:
Régis Behmo 2021-04-27 12:44:44 +02:00
commit 872c00b53c
20 changed files with 274 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
.*.swp
!.gitignore
TODO
__pycache__
*.egg-info/
/build/
/dist/

9
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,9 @@
variables:
TUTOR_PLUGIN: android
TUTOR_IMAGES: android
TUTOR_PYPI_PACKAGE: tutor-android
OPENEDX_RELEASE: lilac
include:
- project: 'community/tutor-ci'
file: 'plugin-gitlab-ci.yml'

2
MANIFEST.in Normal file
View File

@ -0,0 +1,2 @@
recursive-include tutorandroid/patches *
recursive-include tutorandroid/templates *

22
README.rst Normal file
View File

@ -0,0 +1,22 @@
android plugin for `Tutor <https://docs.tutor.overhang.io>`__
===================================================================================
Installation
------------
::
pip install git+https://github.com/overhangio/tutor-android
Usage
-----
::
tutor plugins enable android
License
-------
This software is licensed under the terms of the AGPLv3.

61
setup.py Normal file
View File

@ -0,0 +1,61 @@
import io
import os
from setuptools import setup, find_packages
HERE = os.path.abspath(os.path.dirname(__file__))
def load_readme():
with io.open(os.path.join(HERE, "README.rst"), "rt", encoding="utf8") as f:
return f.read()
def load_about():
about = {}
with io.open(
os.path.join(HERE, "tutorandroid", "__about__.py"),
"rt",
encoding="utf-8",
) as f:
exec(f.read(), about) # pylint: disable=exec-used
return about
ABOUT = load_about()
setup(
name="tutor-android",
version=ABOUT["__version__"],
url="https://github.com/overhangio/tutor-android",
project_urls={
"Code": "https://github.com/overhangio/tutor-android",
"Issue tracker": "https://github.com/overhangio/tutor-android/issues",
},
license="AGPLv3",
author="Overhang.IO",
description="android plugin for Tutor",
long_description=load_readme(),
packages=find_packages(exclude=["tests*"]),
include_package_data=True,
python_requires=">=3.5",
install_requires=["tutor-openedx>=12.0.0,<13.0.0"],
entry_points={
"tutor.plugin.v0": [
"android = tutorandroid.plugin"
]
},
classifiers=[
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU Affero General Public License v3",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
],
)

View File

@ -0,0 +1 @@
__version__ = "12.0.0"

0
tutorandroid/__init__.py Normal file
View File

52
tutorandroid/cli.py Normal file
View File

@ -0,0 +1,52 @@
import click
from tutor.commands.compose import ComposeJobRunner
from tutor.commands.context import Context
from tutor.commands.local import docker_compose as local_docker_compose
from tutor import config as tutor_config
from tutor import env as tutor_env
from tutor import fmt
from tutor.types import Config
@click.group(help="Build an Android app for your Open edX platform")
def android() -> None:
pass
@click.command(help="Build the application")
@click.argument("mode", type=click.Choice(["debug", "release"]))
@click.pass_obj
def build(context: Context, mode: str) -> None:
config = tutor_config.load(context.root)
docker_run(context.root, build_command(config, mode))
fmt.echo_info(
"The {} APK file is available in {}".format(
mode, tutor_env.data_path(context.root, "android")
)
)
def build_command(config: Config, target: str) -> str:
gradle_target = {
"debug": "assembleProdDebuggable",
"release": "assembleProdRelease",
}[target]
apk_folder = {"debug": "debuggable", "release": "release"}[target]
command = """
sed -i "s/APPLICATION_ID = .*/APPLICATION_ID = \\"{{ LMS_HOST|reverse_host|replace("-", "_") }}\\"/g" constants.gradle
./gradlew {gradle_target}
cp OpenEdXMobile/build/outputs/apk/prod/{apk_folder}/*.apk /openedx/data/"""
command = tutor_env.render_str(config, command)
command = command.format(gradle_target=gradle_target, apk_folder=apk_folder)
return command
def docker_run(root: str, command: str) -> None:
config = tutor_config.load(root)
runner = ComposeJobRunner(root, config, local_docker_compose)
runner.run_job("android", command)
android.add_command(build)

0
tutorandroid/patches/.gitignore vendored Normal file
View File

View File

@ -0,0 +1,5 @@
android-job:
image: {{ ANDROID_DOCKER_IMAGE }}
volumes:
- "../android/:/openedx/config/"
- "../../data/android/:/openedx/data/"

37
tutorandroid/plugin.py Normal file
View File

@ -0,0 +1,37 @@
from glob import glob
import os
import pkg_resources
from .__about__ import __version__
from .cli import android as android_command
templates = pkg_resources.resource_filename("tutorandroid", "templates")
config = {
"add": {"OAUTH2_SECRET": "{{ 24|random_string }}"},
"defaults": {
"VERSION": __version__,
"DOCKER_IMAGE": "{{ DOCKER_REGISTRY }}overhangio/openedx-android:{{ ANDROID_VERSION }}",
"RELEASE_STORE_PASSWORD": "android store password",
"RELEASE_KEY_PASSWORD": "android release key password",
"RELEASE_KEY_ALIAS": "android release key alias",
},
}
hooks = {"build-image": {"android": "{{ ANDROID_DOCKER_IMAGE }}"}, "init": ["lms"]}
command = android_command
def patches():
all_patches = {}
patches_dir = pkg_resources.resource_filename("tutorandroid", "patches")
for path in glob(os.path.join(patches_dir, "*")):
with open(path) as patch_file:
name = os.path.basename(path)
content = patch_file.read()
all_patches[name] = content
return all_patches

View File

View File

@ -0,0 +1,3 @@
edx.android {
configFiles = ['tutor.yaml']
}

View File

@ -0,0 +1,4 @@
RELEASE_STORE_FILE=/openedx/config/app.keystore
RELEASE_STORE_PASSWORD={{ ANDROID_RELEASE_STORE_PASSWORD }}
RELEASE_KEY_PASSWORD={{ ANDROID_RELEASE_KEY_PASSWORD }}
RELEASE_KEY_ALIAS={{ ANDROID_RELEASE_KEY_ALIAS }}

View File

@ -0,0 +1,18 @@
# See docs: https://openedx.atlassian.net/wiki/spaces/LEARNER/pages/48792067/App+Configuration+Flags
API_HOST_URL: "{{ "https" if ENABLE_HTTPS else "http" }}://{{ LMS_HOST }}"
ENVIRONMENT_DISPLAY_NAME: "tutor"
PLATFORM_NAME: "{{ PLATFORM_NAME }}"
PLATFORM_DESTINATION_NAME: "{{ LMS_HOST }}"
FEEDBACK_EMAIL_ADDRESS: "{{ CONTACT_EMAIL }}"
OAUTH_CLIENT_ID: "android"
COURSE_VIDEOS_ENABLED: true
CERTIFICATES_ENABLED: true
DISCUSSIONS_ENABLED: true
DISCOVERY:
COURSE:
TYPE: native
DOWNLOAD_TO_SD_CARD_ENABLED: true
NEW_LOGISTRATION_ENABLED: true
USER_PROFILES_ENABLED : true
VIDEO_TRANSCRIPT_ENABLED: true

View File

View File

@ -0,0 +1,40 @@
FROM docker.io/ubuntu:20.04
MAINTAINER Overhang.io <contact@overhang.io>
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && \
apt upgrade -y && \
apt install -y wget unzip git openjdk-8-jre openjdk-8-jdk
RUN mkdir /openedx
# Install Android SDK
# Inspired from https://github.com/LiveXP/docker-android-sdk/blob/master/Dockerfile
ENV ANDROID_SDK_VERSION 6200805
ENV ANDROID_SDK_PATH /openedx/android-sdk
ENV ANDROID_HOME /openedx/android-sdk
RUN mkdir ${ANDROID_HOME}
WORKDIR /openedx/android-sdk
RUN wget https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_VERSION}_latest.zip && \
unzip commandlinetools-linux-${ANDROID_SDK_VERSION}_latest.zip && \
rm commandlinetools-linux-${ANDROID_SDK_VERSION}_latest.zip
# Accept licenses
# https://developer.android.com/studio/command-line/sdkmanager
ARG ANDROID_API_LEVEL=28
RUN yes | /openedx/android-sdk/tools/bin/sdkmanager --sdk_root=${ANDROID_HOME} --install "platforms;android-$ANDROID_API_LEVEL" 1> /dev/null
# Install android app repo
ARG ANDROID_APP_REPOSITORY=https://github.com/edx/edx-app-android
ARG ANDROID_APP_VERSION=release/2.23.2
RUN git clone $ANDROID_APP_REPOSITORY --branch $ANDROID_APP_VERSION /openedx/edx-app-android
WORKDIR /openedx/edx-app-android
# Install gradle and all dependencies
RUN ./gradlew -v
RUN ./gradlew tasks
# User-customized config
COPY ./edx.properties ./OpenEdXMobile/edx.properties
RUN mkdir /openedx/config
RUN ln -s /openedx/config/gradle.properties ./OpenEdXMobile/gradle.properties

View File

@ -0,0 +1 @@
edx.dir = '/openedx/config'

View File

View File

@ -0,0 +1,12 @@
# Delete obsolete credentials for Android application
./manage.py lms shell -c 'from oauth2_provider.models import get_application_model
get_application_model().objects.filter(name="android").exclude(user__username="login_service_user").delete()'
# Create oauth credentials for Android application
./manage.py lms create_dot_application \
--client-id android \
--client-secret {{ ANDROID_OAUTH2_SECRET }} \
--grant-type password \
--public \
--update \
android \
login_service_user