Code Monkey home page Code Monkey logo

mdeluise / plant-it Goto Github PK

View Code? Open in Web Editor NEW
594.0 594.0 20.0 102.43 MB

🪴 Self-hosted, open source gardening companion app

Home Page: https://plant-it.org

License: GNU General Public License v3.0

Dockerfile 0.06% Java 48.00% Gherkin 1.35% Shell 0.59% HTML 1.70% CSS 0.05% Kotlin 0.01% Swift 0.22% Objective-C 0.01% Dart 43.90% CMake 1.72% C++ 2.18% C 0.13% Ruby 0.08%
dart flutter gardening java plants self-hosted self-hosting spring-boot

plant-it's People

Contributors

astappiev avatar cesarblancg avatar codingemil avatar dependabot[bot] avatar fsmeets84 avatar john710 avatar lovelesscodes avatar mascherino avatar mdeluise avatar mega-cookie avatar quentains avatar wallk avatar wpitombeira avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

plant-it's Issues

Display common name while adding a plant (Trefle import)

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

As a user, I would like to see common name displayed when adding a new plant (getting Trefle suggestion) so I can easily check if it's the plant I had in mind

Solution

This feature would display plant's common name on the card and/or inside the species information (when opening the card)
This information comes in "common_name" string from Trefle (if present)

What are alternatives?

Right now I can check the Trefle API/website myself or just google the plant on other resources

Additional context

Here are some mockups how it could look:

Card:
card

Information screen:
info

Missing errors feedback

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

A lot of errors feedback are missing in the UI.
For example: adding a plant with a duplicate name, add a plant with blank name, add an event when backend is not available, etc. produces no changes in the UI.

Solution

UI should handle this type of error and show info about them in order to give the user a feedback of the action.

What are alternatives?

No response

Additional context

No response

Remove a plant

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

A way to remove a plant from "your plants"

Solution

No response

What are alternatives?

No response

Additional context

No response

[Docker] Cannot connect to the backend

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

Plant-it just won't work. I get the Cannot connect to the backend error.
Please, see my environment bellow.

Expected behaviour

It should work, I'm following the instructions.

Steps to reproduce

Edit docker-compose.yml, backend.env and frontend.env to your liking
Run docker compose up -d
Go to http://192.168.1.103:3009 (cf config bellow)
Can access the WebUI, but an error message is displayed.

Local environment

Docker-compse.yml:

version: "3"

name: plant-it
services:
  backend:
    image: msdeluise/plant-it-backend:latest
    env_file: backend.env
    depends_on:
      - db
      - cache
    restart: unless-stopped
    volumes:
      - "/srv/Files/Plant-it/upload-dir:/upload-dir"
    ports:
      - "8089:8080"

  db:
    image: mysql:8.0
    restart: always
    env_file: backend.env
    volumes:
      - "/srv/Files/Plant-it/db:/var/lib/mysql"

  cache:
    image: redis:7.2.1
    restart: always

  frontend:
    image: msdeluise/plant-it-frontend:latest
    env_file: frontend.env
    links:
      - backend
    ports:
      - "3009:3000"

Frontend:

PORT=3009
API_URL=http://192.168.1.103:8089/api #ip of my machine with docker running plant-it
WAIT_TIMEOUT=5000

PAGE_SIZE=25

BROWSER=none

Backend:

MYSQL_HOST=db
MYSQL_PORT=3306
MYSQL_USERNAME=root
MYSQL_PSW=root
MYSQL_ROOT_PASSWORD=root
MYSQL_DATABASE=bootdb

JWT_SECRET=32characterscomplicatedsecret
JWT_EXP=1

USERS_LIMIT=2 # including the admin account, so <= 0 if undefined, >= 2 if defined
UPLOAD_DIR=/upload-dir
API_PORT=8089

CACHE_TTL=86400
CACHE_HOST=cache
CACHE_PORT=6379

TRAFLE_KEY=

ALLOWED_ORIGINS=*

Additional info

No response

Configurable CORS origin through environment variable

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

Currently the backend is hardcoded to only accept requests from http://localhost:3000 1.
This should be made configurable to allow for more flexible setups.

Solution

Add an environment variable (BASE_URL or similar) that is used to set the allowed origin for CORS.
This would mean it could be easily configured for the backend using the docker-compose file.

What are alternatives?

This problem currently circumvented by the nginx reverse-proxy1, which would no longer be required if this were implemented.

Additional context

No response

Footnotes

  1. https://github.com/MDeLuise/plant-it/blob/9456fb4e2822c4ecafc6b2129e69ed1fc997faa1/backend/src/main/java/com/github/mdeluise/plantit/security/ApplicationSecurityConfig.java#L106 2

Cannot login after creating user

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

After creating a user in the platform it automatically logins as this user. However, if attempting to login using these credentials in another device, browser, or in the same browser (after whipping data) it gives a bad credentials error.

I've tried creating multiple users and this error happens always. In the backend logs I see something like Temporary password for user MyUsername not found. I don't have access to the logs now, but I can post them later.

Thank you so much for your work!

Expected behaviour

No response

Steps to reproduce

No response

Local environment

Running on a RPI 4 with debian bookworm 64bits. Latest docker version with reverse proxy using nginx. I'll post my config later!

docker-compose:

version: "3"
name: plant-it
services:
  backend:
    image: msdeluise/plant-it-backend:latest
    env_file: backend.env
    depends_on:
      - db
      - cache
    restart: unless-stopped
    volumes:
      - "./upload-dir:/upload-dir"
      - "./certs:/certificates"
    ports:
      - "8089:8080"
  db:
    image: mysql:8.0
    restart: always
    env_file: backend.env
    volumes:
      - "./db:/var/lib/mysql"
  cache:
    image: redis:7.2.1
    restart: always
  frontend:
    image: msdeluise/plant-it-frontend:latest
    env_file: frontend.env
    links:
      - backend
    ports:
      - "3009:3000"
    volumes:
      - "./certs:/certificates"
volumes:
  certs:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: ./certificates

Backend:

#
# DB
#
MYSQL_HOST=db
MYSQL_PORT=3306
MYSQL_USERNAME=root
MYSQL_PSW=myroot
MYSQL_ROOT_PASSWORD=myroot
MYSQL_DATABASE=bootdb

#
# JWT
#
JWT_SECRET=llllcharacterscomplicatedsecret
JWT_EXP=1

#
# Server config
#
USERS_LIMIT=2
UPLOAD_DIR=/upload-dir
API_PORT=8080
TREFLE_KEY=mykey
ALLOWED_ORIGINS=https://plantit.mysite.com
#
# Cache
#
CACHE_TTL=86400
CACHE_HOST=cache
CACHE_PORT=6379

#
# SSL
#
SSL_ENABLED=false
CERTIFICATE_PATH=/certificates/

LOG_LEVEL=DEBUG

Frontend:

PORT=3000
API_URL=https://plantitdb.mysite.com/api
WAIT_TIMEOUT=50000
PAGE_SIZE=25
BROWSER=none
SSL_ENABLED=true
CERTIFICATE_PATH=/certificates/

Logs:

afe use of the session): org.hibernate.AssertionFailure: force initializing collection loading
2024-04-15T13:45:34.247Z ERROR 14 --- [nio-8080-exec-6] c.g.m.p.n.p.TemporaryPasswordService     : Temporary password not found for user Planti
2024-04-15T13:45:41.854Z ERROR 14 --- [nio-8080-exec-3] c.g.m.p.n.p.TemporaryPasswordService     : Temporary password not found for user Planti
2024-04-15T13:45:45.899Z ERROR 14 --- [nio-8080-exec-1] c.g.m.p.n.p.TemporaryPasswordService     : Temporary password not found for user Planti
2024-04-15T22:24:54.612Z DEBUG 14 --- [io-8080-exec-10] c.g.m.p.systeminfo.SystemVersionService  : retrieve the system version info from GitHub.
2024-04-15T22:24:54.830Z DEBUG 14 --- [nio-8080-exec-5] c.g.mdeluise.plantit.plant.PlantService  : Search for DB saved plants
2024-04-15T22:24:54.894Z DEBUG 14 --- [nio-8080-exec-3] c.g.m.p.p.PlantInfoExtractorFacade       : Search all botanical info
2024-04-15T22:24:54.895Z DEBUG 14 --- [nio-8080-exec-3] c.g.m.p.b.BotanicalInfoService           : Search for DB saved botanical info (max size 5)
2024-04-15T22:24:54.919Z DEBUG 14 --- [nio-8080-exec-3] c.g.m.p.p.trafle.TrefleRequestMaker      : Fetching all info from Trefle
2024-04-15T22:25:14.543Z ERROR 14 --- [nio-8080-exec-5] c.g.m.p.n.p.TemporaryPasswordService     : Temporary password not found for user Plantae
2024-04-16T07:30:00.003Z  INFO 14 --- [   scheduling-1] c.g.m.p.reminder.ReminderDispatcher      : Starting reminder dispatching...

Additional info

No response

Upload image with alpha channel result in error

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

Uploading an image with alpha channel result in exception.
A possible solution could be this.

Expected behaviour

The image should be displayed without error.

Steps to reproduce

  1. upload a plant's image with alpha channel
  2. try to view the uploaded image

Local environment

No response

Additional info

No response

Cannot connect to the backend

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

I have used the configuration options in both of these examples.

https://docs.plant-it.org/installation/configurations/ as well as https://pimylifeup.com/raspberry-pi-plant-it/

The only change made to the configurations is on the IP. I use 192.168.1.120.

But I still get this error in both attempts.

I see a closed ticket that addressed this issue, but I still need help getting this to work.

Thanks

Expected behaviour

n/a

Steps to reproduce

n/a

Local environment

n/a

Additional info

n/a

Custom `botanical info` should be available right after the creation

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

When creating a plant with a custom botanical info, the newer created botanical info should be available immediately.

Expected behaviour

No response

Steps to reproduce

  1. go to search tab
  2. create a plant with a custom botanical info
  3. check the search tab result (the new botanical info is not available before a refresh of the page)

Local environment

No response

Additional info

No response

Unable to connect to Redis (Docker)

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

When I open the frontend in browser and log in -- I get "Unable to connect to Redis" notification

I'm not sure where "cache/:6379" and such comes from
This redis container uses default config and the same port
Does the application expects service name "cache" and nothing else?

Expected behaviour

No response

Steps to reproduce

No response

Local environment

It's a docker deployment
Here's a relevant part of docker-compose.yaml:

  # === PLANT-IT ===
  plant-it-backend:
    container_name: plant-it-backend
    image: msdeluise/plant-it-backend:latest
    env_file: ./envs/plant-it-backend.env
    depends_on:
      - mariadb
      - redis-cache
    volumes:
      - "./volumes/plant-it/upload-dir:/upload-dir"
      - "./volumes/plant-it/certs:/certificates"
      # - "certs:/certificates" #bound to tmpfs or something similar?
    ports:
      - "3001:8080" #API port
    restart: unless-stopped

  plant-it-frontend:
    container_name: plant-it-frontend
    image: msdeluise/plant-it-frontend:latest
    env_file: ./envs/plant-it-frontend.env
    links:
      - plant-it-backend
    ports:
      - "3000:3000" #frontend port
    volumes:
      - "./volumes/plant-it/certs:/certificates"
      # - "certs:/certificates" #virtual fs of some kind?
    restart: unless-stopped

  #MySQL (mariadb) DB for inventree and plant-it
  mariadb:
    container_name: mariadb
    image: lscr.io/linuxserver/mariadb:latest
    env_file:
      - ./envs/mariadb.env
      - ./envs/plant-it-backend.env
    ports:
      - "3306:3306"
    volumes:
      - ./volumes/mariadb/config:/config
      - ./volumes/mariadb/db_backup:/backup
    restart: unless-stopped

  # redis acts as database cache manager for inventree and plant-it
  redis-cache:
    container_name: redis-cache
    image: redis:7.2.1
    depends_on:
      - mariadb
    # profiles:
    #     - redis
    env_file:
      - ./envs/inventree.env
    expose:
      - ${INVENTREE_CACHE_PORT:-6379}
    restart: always

Relevant part of plant-it-backend.env:

#
# Cache
#
CACHE_TTL=86400
CACHE_HOST=cache
CACHE_PORT=6379

Additional info

Part of redis log:

1:C 09 Apr 2024 13:04:22.516 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 09 Apr 2024 13:04:22.516 * Redis version=7.2.1, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 09 Apr 2024 13:04:22.516 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
1:M 09 Apr 2024 13:04:22.519 * monotonic clock: POSIX clock_gettime
1:M 09 Apr 2024 13:04:22.528 * Running mode=standalone, port=6379.
1:M 09 Apr 2024 13:04:22.533 * Server initialized
1:M 09 Apr 2024 13:04:22.541 * Loading RDB produced by version 7.2.1
1:M 09 Apr 2024 13:04:22.541 * RDB age 2 seconds
1:M 09 Apr 2024 13:04:22.542 * RDB memory usage when created 0.93 Mb
1:M 09 Apr 2024 13:04:22.542 * Done loading RDB, keys loaded: 2, keys expired: 0.
1:M 09 Apr 2024 13:04:22.542 * DB loaded from disk: 0.009 seconds
1:M 09 Apr 2024 13:04:22.542 * Ready to accept connections tcp

Part of backend container log (this is the whole thing I can see in portainer):

2024-04-09T13:07:21.524Z  INFO 10 --- [           main] c.g.mdeluise.plantit.ApplicationConfig   : UPDATE_EXISTING flag set to false. Skipping update of existing species.
2024-04-09T13:07:23.716Z ERROR 10 --- [   scheduling-1] o.s.s.s.TaskUtils$LoggingErrorHandler    : Unexpected error occurred in scheduled task
org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis
	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.translateException(LettuceConnectionFactory.java:1602) ~[spring-data-redis-3.0.0.jar!/:3.0.0]
	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.getConnection(LettuceConnectionFactory.java:1533) ~[spring-data-redis-3.0.0.jar!/:3.0.0]
	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.getNativeConnection(LettuceConnectionFactory.java:1358) ~[spring-data-redis-3.0.0.jar!/:3.0.0]
	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.getConnection(LettuceConnectionFactory.java:1341) ~[spring-data-redis-3.0.0.jar!/:3.0.0]
	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.getSharedConnection(LettuceConnectionFactory.java:1059) ~[spring-data-redis-3.0.0.jar!/:3.0.0]
	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.getConnection(LettuceConnectionFactory.java:398) ~[spring-data-redis-3.0.0.jar!/:3.0.0]
	at org.springframework.data.redis.cache.DefaultRedisCacheWriter.execute(DefaultRedisCacheWriter.java:272) ~[spring-data-redis-3.0.0.jar!/:3.0.0]
	at org.springframework.data.redis.cache.DefaultRedisCacheWriter.clean(DefaultRedisCacheWriter.java:189) ~[spring-data-redis-3.0.0.jar!/:3.0.0]
	at org.springframework.data.redis.cache.RedisCache.clear(RedisCache.java:190) ~[spring-data-redis-3.0.0.jar!/:3.0.0]
	at org.springframework.data.redis.cache.RedisCache.clear(RedisCache.java:178) ~[spring-data-redis-3.0.0.jar!/:3.0.0]
	at org.springframework.cache.interceptor.AbstractCacheInvoker.doClear(AbstractCacheInvoker.java:122) ~[spring-context-6.0.3.jar!/:6.0.3]
	at org.springframework.cache.interceptor.CacheAspectSupport.performCacheEvict(CacheAspectSupport.java:505) ~[spring-context-6.0.3.jar!/:6.0.3]
	at org.springframework.cache.interceptor.CacheAspectSupport.processCacheEvicts(CacheAspectSupport.java:493) ~[spring-context-6.0.3.jar!/:6.0.3]
	at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:434) ~[spring-context-6.0.3.jar!/:6.0.3]
	at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:345) ~[spring-context-6.0.3.jar!/:6.0.3]
	at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:64) ~[spring-context-6.0.3.jar!/:6.0.3]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.0.3.jar!/:6.0.3]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) ~[spring-aop-6.0.3.jar!/:6.0.3]
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) ~[spring-aop-6.0.3.jar!/:6.0.3]
	at com.github.mdeluise.plantit.ApplicationConfig$$SpringCGLIB$$3.cacheEvict(<generated>) ~[classes!/:0.4.3]
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
	at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) ~[spring-context-6.0.3.jar!/:6.0.3]
	at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-6.0.3.jar!/:6.0.3]
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572) ~[na:na]
	at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:358) ~[na:na]
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) ~[na:na]
	at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]
Caused by: org.springframework.data.redis.connection.PoolException: Could not get a resource from the pool
	at org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider.getConnection(LettucePoolingConnectionProvider.java:105) ~[spring-data-redis-3.0.0.jar!/:3.0.0]
	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.getConnection(LettuceConnectionFactory.java:1531) ~[spring-data-redis-3.0.0.jar!/:3.0.0]
	... 28 common frames omitted
Caused by: io.lettuce.core.RedisConnectionException: Unable to connect to cache/<unresolved>:6379
	at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:78) ~[lettuce-core-6.2.2.RELEASE.jar!/:6.2.2.RELEASE]
	at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:56) ~[lettuce-core-6.2.2.RELEASE.jar!/:6.2.2.RELEASE]
	at io.lettuce.core.AbstractRedisClient.getConnection(AbstractRedisClient.java:350) ~[lettuce-core-6.2.2.RELEASE.jar!/:6.2.2.RELEASE]
	at io.lettuce.core.RedisClient.connect(RedisClient.java:216) ~[lettuce-core-6.2.2.RELEASE.jar!/:6.2.2.RELEASE]
	at org.springframework.data.redis.connection.lettuce.StandaloneConnectionProvider.lambda$getConnection$1(StandaloneConnectionProvider.java:111) ~[spring-data-redis-3.0.0.jar!/:3.0.0]
	at java.base/java.util.Optional.orElseGet(Optional.java:364) ~[na:na]
	at org.springframework.data.redis.connection.lettuce.StandaloneConnectionProvider.getConnection(StandaloneConnectionProvider.java:111) ~[spring-data-redis-3.0.0.jar!/:3.0.0]
	at org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider.lambda$getConnection$0(LettucePoolingConnectionProvider.java:93) ~[spring-data-redis-3.0.0.jar!/:3.0.0]
	at io.lettuce.core.support.ConnectionPoolSupport$RedisPooledObjectFactory.create(ConnectionPoolSupport.java:211) ~[lettuce-core-6.2.2.RELEASE.jar!/:6.2.2.RELEASE]
	at io.lettuce.core.support.ConnectionPoolSupport$RedisPooledObjectFactory.create(ConnectionPoolSupport.java:201) ~[lettuce-core-6.2.2.RELEASE.jar!/:6.2.2.RELEASE]
	at org.apache.commons.pool2.BasePooledObjectFactory.makeObject(BasePooledObjectFactory.java:70) ~[commons-pool2-2.11.1.jar!/:2.11.1]
	at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:571) ~[commons-pool2-2.11.1.jar!/:2.11.1]
	at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:298) ~[commons-pool2-2.11.1.jar!/:2.11.1]
	at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:223) ~[commons-pool2-2.11.1.jar!/:2.11.1]
	at io.lettuce.core.support.ConnectionPoolSupport$1.borrowObject(ConnectionPoolSupport.java:122) ~[lettuce-core-6.2.2.RELEASE.jar!/:6.2.2.RELEASE]
	at io.lettuce.core.support.ConnectionPoolSupport$1.borrowObject(ConnectionPoolSupport.java:117) ~[lettuce-core-6.2.2.RELEASE.jar!/:6.2.2.RELEASE]
	at org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider.getConnection(LettucePoolingConnectionProvider.java:99) ~[spring-data-redis-3.0.0.jar!/:3.0.0]
	... 29 common frames omitted
Caused by: java.net.UnknownHostException: cache: Name or service not known
	at java.base/java.net.Inet6AddressImpl.lookupAllHostAddr(Native Method) ~[na:na]
	at java.base/java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:52) ~[na:na]
	at java.base/java.net.InetAddress$PlatformResolver.lookupByName(InetAddress.java:1211) ~[na:na]
	at java.base/java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1828) ~[na:na]
	at java.base/java.net.InetAddress$NameServiceAddresses.get(InetAddress.java:1139) ~[na:na]
	at java.base/java.net.InetAddress.getAllByName0(InetAddress.java:1818) ~[na:na]
	at java.base/java.net.InetAddress.getAllByName(InetAddress.java:1688) ~[na:na]
	at java.base/java.net.InetAddress.getByName(InetAddress.java:1568) ~[na:na]
	at io.netty.util.internal.SocketUtils$8.run(SocketUtils.java:156) ~[netty-common-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.util.internal.SocketUtils$8.run(SocketUtils.java:153) ~[netty-common-4.1.86.Final.jar!/:4.1.86.Final]
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:571) ~[na:na]
	at io.netty.util.internal.SocketUtils.addressByName(SocketUtils.java:153) ~[netty-common-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.resolver.DefaultNameResolver.doResolve(DefaultNameResolver.java:41) ~[netty-resolver-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.resolver.SimpleNameResolver.resolve(SimpleNameResolver.java:61) ~[netty-resolver-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.resolver.SimpleNameResolver.resolve(SimpleNameResolver.java:53) ~[netty-resolver-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.resolver.InetSocketAddressResolver.doResolve(InetSocketAddressResolver.java:55) ~[netty-resolver-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.resolver.InetSocketAddressResolver.doResolve(InetSocketAddressResolver.java:31) ~[netty-resolver-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.resolver.AbstractAddressResolver.resolve(AbstractAddressResolver.java:106) ~[netty-resolver-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.bootstrap.Bootstrap.doResolveAndConnect0(Bootstrap.java:206) ~[netty-transport-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.bootstrap.Bootstrap.access$000(Bootstrap.java:46) ~[netty-transport-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.bootstrap.Bootstrap$1.operationComplete(Bootstrap.java:180) ~[netty-transport-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.bootstrap.Bootstrap$1.operationComplete(Bootstrap.java:166) ~[netty-transport-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:590) ~[netty-common-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:557) ~[netty-common-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:492) ~[netty-common-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:636) ~[netty-common-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.util.concurrent.DefaultPromise.setSuccess0(DefaultPromise.java:625) ~[netty-common-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:105) ~[netty-common-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.channel.DefaultChannelPromise.trySuccess(DefaultChannelPromise.java:84) ~[netty-transport-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.channel.AbstractChannel$AbstractUnsafe.safeSetSuccess(AbstractChannel.java:990) ~[netty-transport-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.channel.AbstractChannel$AbstractUnsafe.register0(AbstractChannel.java:516) ~[netty-transport-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.channel.AbstractChannel$AbstractUnsafe.access$200(AbstractChannel.java:429) ~[netty-transport-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.channel.AbstractChannel$AbstractUnsafe$1.run(AbstractChannel.java:486) ~[netty-transport-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174) ~[netty-common-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167) ~[netty-common-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470) ~[netty-common-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569) ~[netty-transport-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.86.Final.jar!/:4.1.86.Final]
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.86.Final.jar!/:4.1.86.Final]
	... 1 common frames omitted

Upload multiple images

Discussed in #100

Originally posted by MDeLuise February 6, 2024

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

It would be useful to have the possibility of uploading multiple plant's images at ones.

Solution

No response

What are alternatives?

No response

Additional context

No response

SMTP configuration

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

As discussed in this thread, it would be beneficial to incorporate an SMTP configuration into the project.
This feature holds great potential, particularly in user signup processes and enabling future functionality such as email notifications for plant-related tasks.

One key consideration for implementing SMTP is to ensure that it remains optional. Users should have the flexibility to choose whether or not to utilize an SMTP server based on their preferences. This approach allows for seamless integration into various (self) hosting environments and accommodates users who may not require email notifications.

Solution

No response

What are alternatives?

No response

Additional context

No response

Place modified event correctly

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

When a event's date is modified, the event is not placed correctly in the list (i.e. sorted by date)

Expected behaviour

No response

Steps to reproduce

  1. modify an existing event's date
  2. check the result after the edit

Local environment

No response

Additional info

No response

Cannot connect to backend

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

When I run the application on Linux with docker compose and the ports that have been previously discussed I keep getting this error. (This is using both custom docker-compose.yml and the example ones set out in the guide)

Expected behaviour

Correct connection to backend.

Steps to reproduce

Add docker-compose.yml , backend.env and frontend.env in your directory
Run sudo docker-compose up -d

Local environment

Running in docker on linux vm. Other docker compose apps run fine. I have added the log file in which I think the error is occuring!

Additional info

_plant-it-backend-1_logs.txt

Please let me know if you need anymore info! I am super excited to get this up and running

Support for linux/arm/v7 docker image for Raspberry Pi 4

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

I would like to self-host plant-it on my Raspberry Pi 4. For that, I'd require a Docker image built for linux/arm/v7.

When running the following command on my Raspberry Pi 4:

docker pull msdeluise/plant-it-backend:latest

I get the following error:

no matching manifest for linux/arm/v7 in the manifest list entries

Solution

  • Build the docker image for linux/arm/v7
  • Add an installation instruction for Raspberry Pi specifically (MySQL Docker image also doesn't support armv7 out of the box, maybe this image works instead?

What are alternatives?

No response

Additional context

No response

Unsanitized error messages on login/sign-up page

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

Raw error messages are displayed when:

  • No username and/or password is supplied (login and sign-up)
  • The provided username is not between 3 and 20 characters long (sign-up)
  • The provided password is not between 6 and 40 characters long (sign-up)

Expected behaviour

No response

Steps to reproduce

No response

Additional info

Output for a missing password on the login page:

Validation failed for argument [0] in public org.springframework.http.ResponseEntity<com.github.mdeluise.plantit.authentication.payload.response.UserInfoResponse> com.github.mdeluise.plantit.authentication.AuthController.authenticateUser(com.github.mdeluise.plantit.authentication.payload.request.LoginRequest): [Field error in object 'loginRequest' on field 'password': rejected value []; codes [NotBlank.loginRequest.password,NotBlank.password,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [loginRequest.password,password]; arguments []; default message [password]]; default message [must not be blank]] 

Additional fields and event types

Discussed in #97

Originally posted by fludstank February 4, 2024

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

First of all, this has been absolutely fantastic and really helpful for keeping track of my plants. A couple of elements that would be great in the Plant Stats field that I've been using the notes for, but might be helpful to have as their own fields have been

  • purchase price
  • where purchased/seller info/person who gifted
  • physical location (which room, tray number, home, office, offsite location, etc)
  • link the plant/tag as a propagation of another in the collection

Related to the last one, it would also be helpful to have an event for propagating. Unrelated to that would be events for pruning and repotting (I've been using transplanting but idk if that's technically the same or not).

Even if these enhancements don't make it, I'm still going to be a huge fan and will be recommending it to my self hosting plant enthusiast friends!

Solution

No response

What are alternatives?

No response

Additional context

No response

URL in Getting Started Section Wrong

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

The URL in the README.md (https://github.com/MDeLuise/plant-it/blob/main/README.md) for www.plant-it.org is not working.

Expected behaviour

I would expect the www.plant-it.org site to be up and running.

Steps to reproduce

go to www.plant-it.org
get nx domain error

Additional info

Looks like the domain is for sale. https://whois.domaintools.com/plant-it.org

Can't use Local environment

Question

Hi! I attempted to run it in my local environment to experiment with new features, but I’m unable to set the API key.

Steps:

Clone the repository.
Set the Trefle API key in the .env file.
Launch it with “./mvnw spring-boot:run -Dspring-boot.run.profiles=dev -DcopyFiles”.
Log in with user/user credentials.
How can I set the API key? It’s showing an error.

Introduce entity relationships

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

This feature request proposes the implementation of entity relationships within the system to enhance data connectivity and navigation between different entities.

Background:

Currently, the system lacks explicit relationships between entities, which limits the ability to navigate seamlessly between related data points. By introducing entity relationships, users can efficiently explore interconnected data and gain deeper insights into the relationships between various entities.

Proposed Changes:

  1. Establish Linkages Between Entities:
    • Implement functionality to establish relationships between different entities, such as plants, species, propagations, and collections.
    • Allow users to define and manage relationships through intuitive interfaces.
  2. View Species from Plants:
    • Enable users to click on a plant entity to view its associated species.
    • Provide a convenient link or navigation option from plant details to the corresponding species information.
  3. Track Propagations:
    • Introduce a feature to list propagations associated with each plant.
    • Allow users to easily access and manage propagation records linked to specific plants.
  4. Manage Collections:
    • Enable users to track collections of plants, such as plants sharing the same pot or location.
    • Implement functionality to group related plants into collections for easier organization and management.

Importance:

Introducing entity relationships adds a layer of depth and connectivity to the system, enabling users to explore and understand the interdependencies between different entities more effectively. By facilitating seamless navigation and data access, this feature enhances user experience and productivity within the application.

This feature request outlines the necessary changes to implement entity relationships and underscores their importance in enriching the system's functionality and usability.

Solution

No response

What are alternatives?

No response

Additional context

No response

Events in plant detail

Question

Hi!
I'm trying out your project and I don't understand the use of the events.

When you're in plant details,  the button "add event" doesn't do anything or shows anything in the logs.
When I manually add an event from the main menu, it doesn't appear in the "Events" section in plant details.

Plant care information

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

I understand that there is a notes field.
It would be nice to have plant-it to keep plant care information. For example,

  1. Light requirements. Full Sun, Part Sun, Shade etc.
  2. Water requirements. Every N days.
  3. Temperature requirements, Max, Min and Ideal.

In colder regions, there are events to move plant outside and move back inside.

Solution

No response

What are alternatives?

No response

Additional context

No response

Uncaught (in promise) - AxiosError timeout 5000ms

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

I'm getting lots of AxiosError timeouts when having a lot of plants loading custom images. This happens every time I am reloading the website after being logged in to the account.

image

I am running the service on a subdomain of a domain I own and the service works flawlessly except for not loading all images on the homepage and making several of the plants seem to be loading.

image

Expected behaviour

No response

Steps to reproduce

  1. Have more than 5-6 plants with custom images for all of them.
  2. Log into the website
  3. ???
  4. Profit?

Additional info

No response

Backend error when trying to add plant

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

When trying to add a new plant via the search option I get following error as response:
{ "statusCode": 500, "errorCode": "INTERNAL_SERVER_ERROR", "message": "Could not commit JPA transaction" }
In the backend logs nothing is shown

Expected behaviour

No response

Steps to reproduce

No response

Local environment

No response

Additional info

No response

Change plant's thumbnail

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

Discussion #54 points out that it would be useful to have the possibility of choosing the plants' thumbnail instead of using the default Trefle one.

Solution

  • On frontend side this could be done adding an entry in the plant detail named "Plant thumbnail". That entry could accept a new image to upload or a URL. It would be also useful to "star" an already uploaded image in order to use it as thumbnail.
  • On backend side it could be added the thumbnail field in the Plant object.

Conversation #54 also points out that would be useful to have the possibility of choosing as thumbnail:

  • a predefined image (uploaded or referenced via URL)
  • the last uploaded plant's image
  • a random image from the plant's uploaded once

What are alternatives?

No response

Additional context

No response

405 error

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

After deploying the plant-it app on a Raspberry Pi using Portainer and Ubuntu, I encounter a 405 error when attempting to create an account or log in. The error message is displayed in a popup with an empty message body.

image

version: "3"
name: plant-it
services:
  backend:
    image: msdeluise/plant-it-backend:latest
    env_file: stack.env
    depends_on:
      - db
      - cache
    restart: unless-stopped
    volumes:
      - "./upload-dir:/upload-dir"
      - "./certificates:/certificates"
    ports:
      - "9092:8080"

  db:
    image: mysql:8.0
    restart: always
    env_file: stack.env
    volumes:
      - "./db:/var/lib/mysql"
    ports:
      - "3307:3306"

  cache:
    image: redis:7.2.1
    restart: always

  frontend:
    image: msdeluise/plant-it-frontend:latest
    env_file: stack.env
    links:
      - backend
    ports:
      - "3090:3000"
    volumes:
      - "./certificates:/certificates"
volumes:
  certs:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: ./certificates

Expected behaviour

I would expect the account creation or login process to complete successfully without any errors, allowing me to access the plant-it app's features.

Steps to reproduce

Deploy the plant-it app using the provided docker-compose file on a Raspberry Pi with Portainer and Ubuntu.
Navigate to the frontend service on port 3090.
Attempt to create a new account or log in with existing credentials.
Observe the 405 error in a popup window.

Local environment

Raspberry Pi model: 4B
Ubuntu version: 22.01
Portainer version: 2.19.4
Browser and version: Edge v122.0.2365.92

Additional info

The docker-compose file has been configured to expose the backend service on port 9092 and the frontend on port 3090.
The database service is exposed on port 3307.
The error occurs when the frontend service makes a POST request to the /api/authentication/signup endpoint.
Screenshot of the error is attached (attach the screenshot you provided).

Add more info sources

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

It would be useful to enhance the app by incorporating additional information sources. This not only provides users with more comprehensive data but also serves as a backup in the event that the Trefle API service becomes unavailable or the user does not have access to network.

Solution

During initial exploration, I came across this service as a potential information source for plants. Notably, the database can be downloaded in CSV format from here. A feasible approach would be to parse this file during the app's startup, allowing for the storage of all species contained within it in the app's database.

What are alternatives?

Other services could be used, if you find any please add them in this conversation.

Additional context

Currently, the app uses only Trefle species and "local" species. Consequently, when searching for a species, the user is presented with a maximum of two choices for the same species. To accommodate the expansion of services for retrieving species information, a decision must be made regarding the handling of duplicated species. One approach is to offer only the most detailed entry to the user. Alternatively, all duplicated species from the employed services could be provided, each species tagged by service — using labels such as "Trefle," "Custom," "USDA," and so on.

Missing more deep project documentation

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

Right now the documentation of the project is condensed in the README.md file.
It would be useful to have a more deep documentation hosted somewhere else, while keeping the README.md as overall introduction.

Solution

It could be used readme or mkdocs

What are alternatives?

No response

Additional context

No response

Plant event reminder

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

Introduce a new feature to the plant management system that allows users to set reminders for specific actions related to their plants. This feature aims to enhance user experience and ensure timely care of plants by enabling users to schedule reminders for essential tasks such as watering, fertilizing, pruning, etc.

The addition of a reminder system to the plant management platform will empower users to stay organized and attentive to their plants' needs, fostering a more enjoyable and successful gardening experience.

Solution

  1. Reminder Settings: Users can define custom reminders for each plant, specifying the type of action (e.g., watering, fertilizing), frequency (e.g., daily, weekly, monthly), and preferred notification method (e.g., email, push notification).

  2. Automated Notifications: The system will automatically send notifications to users according to the scheduled reminders. If no action related to the reminder is logged within the specified time frame, the system will send a notification to remind the user.

  3. Action Tracking: Users can log actions related to the reminders, such as watering a plant. The system will track these actions to ensure that reminders are triggered accurately and provide insights into plant care activities.

  4. Flexible Configuration: Users can easily edit, delete, or temporarily disable reminders based on their changing needs or circumstances.

What are alternatives?

No response

Additional context

No response

Frontend refactoring and restructuring

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

This feature request outlines a plan to refactor and restructure the frontend of the system before the first major release (1.0.0) of the project.

Background

The current frontend lacks a cohesive design and structure, as it was initially developed without clear style guidelines. To improve user experience and coherence across views, it's essential to implement significant changes.

Proposed Changes

  1. Improved Design and Consistency:
    • Enhance the overall look and feel of the application.
    • Establish consistent styling and design elements throughout the interface.
  2. Structural Refactoring:
    • Restructure the frontend to incorporate a more modular and organized approach.
    • Currently, the frontend comprises only two pages: login and the main app. It's crucial to expand this structure to include multiple pages, such as:
      • Species view
      • Plant view
      • Search functionality
      • Settings page
      • And more, as needed
  3. Enhanced User Experience:
    • Introduce additional pages to facilitate seamless navigation and task completion.
    • Implement shortcuts or direct links to specific views for improved user efficiency.
    • Ensure intuitive user flows and interactions across all pages.
  4. Responsive Design:
    • Optimize the frontend for responsiveness across various devices, including tablets and PCs.
    • Ensure that the application is visually appealing and functional on both small and large screens.
    • Implement responsive design principles to adapt layout and content based on screen size and orientation.

Importance

While this may not be an immediate concern, refining the frontend architecture and design is crucial before the project reaches its 1.0.0 release. These changes will contribute to a more polished and user-friendly application, enhancing its overall quality and usability.

This feature request serves as a roadmap for the frontend enhancements required to achieve a more cohesive and effective user interface before the milestone release.

Solution

Maybe starting again from scratch it would be better.

What are alternatives?

No response

Additional context

No response

Build backend

Question

Hi! When I tried to build the backend using ./mvnw spring-boot:run, it showed the following error: maven-wrapper.properties no such file or directory. Maybe you should include the folder in the git repository? I have never used Maven before.

SMTP error

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

Hi and thanks for your work! I really love this project.
I just have a little issue that I couldn't solve. 🥲
Yesterday, I tried to add the SMTP function, but when I add the SMTP lines in my .env file, my backend gets blocked.
I don't understand why.

Sorry for the inconvenience and thanks in advance for your response. 🙏

Expected behaviour

No response

Steps to reproduce

  1. I'm re-pull image and redeploy after each modification
  2. All the containers are on

Local environment

I'm using this project with Portainer.

Here's my Docker Compose file:

version: "3"
name: plant-it
services:
  backend:
    image: msdeluise/plant-it-backend:latest
    container_name: plant-back
    env_file: stack.env
    depends_on:
      - db
      - cache
    restart: unless-stopped
    volumes:
      - "./upload-dir:/upload-dir"
      - "certs:/certificates"

    ports:
      - "91:8080"

  db:
    image: mysql:8.0
    container_name: plant-db
    restart: always
    env_file: stack.env
    volumes:
      - "./db:/var/lib/mysql"
    ports:
      - "3307:3306"

  cache:
    image: redis:7.2.1
    restart: always

  frontend:
    image: msdeluise/plant-it-frontend:latest
    container_name: plant-front
    env_file: stack.env
    links:
      - backend
    ports:
      - "90:3000"
    volumes:
      - "certs:/certificates"
volumes:
  certs:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: ./certificates

Here's my stack.env file:

MYSQL_HOST=db
MYSQL_USERNAME=root
MYSQL_PSW=root
MYSQL_ROOT_PASSWORD=root
MYSQL_DATABASE=bootdb
JWT_SECRET=putTheSecretHere
JWT_EXP=1
USERS_LIMIT=-1
UPLOAD_DIR=/upload-dir
API_PORT=8080
TREFLE_KEY=my-key
ALLOWED_ORIGINS=*
LOG_LEVEL=DEBUG
UPDATE_EXISTING=false
CACHE_TTL=86400
CACHE_HOST=cache
CACHE_PORT=6379
CERTIFICATE_PATH=/certificates/
PORT=3000
API_URL=http://ip-of-my-cloud:91/api/
WAIT_TIMEOUT=10000
CACHE_TTL_DAYS=7
BROWSER=none
SSL_ENABLED=false
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_EMAIL=[email protected]
SMTP_PASSWORD=xxxx xxxx xxxx xxxx
SMTP_AUTH=true
SMTP_START_TTL=true
CONTACT_MAIL=[email protected]

Additional info

Here are my logs in back container with the SMTP lines :
complet logs here

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.0.1)
2024-03-29T09:45:03.347Z  INFO 10 --- [           main] c.github.mdeluise.plantit.Application    : Starting Application v0.4.3 using Java 21.0.2 with PID 10 (/opt/app/app.jar started by root in /)
2024-03-29T09:45:03.349Z DEBUG 10 --- [           main] c.github.mdeluise.plantit.Application    : Running with Spring Boot v3.0.1, Spring v6.0.3
2024-03-29T09:45:03.350Z  INFO 10 --- [           main] c.github.mdeluise.plantit.Application    : No active profile set, falling back to 1 default profile: "default"
2024-03-29T09:45:05.760Z  INFO 10 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode
2024-03-29T09:45:05.762Z  INFO 10 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2024-03-29T09:45:06.057Z  INFO 10 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 286 ms. Found 11 JPA repository interfaces.
2024-03-29T09:45:06.086Z  INFO 10 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode
2024-03-29T09:45:06.088Z  INFO 10 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Redis repositories in DEFAULT mode.
2024-03-29T09:45:06.124Z  INFO 10 --- [           main] .RepositoryConfigurationExtensionSupport : Spring Data Redis - Could not safely identify store assignment for repository candidate interface com.github.mdeluise.plantit.plant.PlantRepository; If you want this repository to be a Redis repository, consider annotating your entities with one of these annotations: org.springframework.data.redis.core.RedisHash (preferred), or consider extending one of the following types with your repository: org.springframework.data.keyvalue.repository.KeyValueRepository
2024-03-29T09:45:06.126Z  INFO 10 --- [           main] .RepositoryConfigurationExtensionSupport : Spring Data Redis - Could not safely identify store assignment for repository candidate interface com.github.mdeluise.plantit.security.apikey.ApiKeyRepository; If you want this repository to be a Redis repository, consider annotating your entities with one of these annotations: org.springframework.data.redis.core.RedisHash (preferred), or consider extending one of the following types with your repository: org.springframework.data.keyvalue.repository.KeyValueRepository
2024-03-29T09:45:06.126Z  INFO 10 --- [           main] .RepositoryConfigurationExtensionSupport : Spring Data Redis - Could not safely identify store assignment for repository candidate interface com.github.mdeluise.plantit.notification.password.TemporaryPasswordRepository; If you want this repository to be a Redis repository, consider annotating your entities with one of these annotations: org.springframework.data.redis.core.RedisHash (preferred), or consider extending one of the following types with your repository: org.springframework.data.keyvalue.repository.KeyValueRepository

[...]

2024-03-29T09:45:06.135Z  INFO 10 --- [           main] .RepositoryConfigurationExtensionSupport : Spring Data Redis - Could not safely identify store assignment for repository candidate interface com.github.mdeluise.plantit.authentication.UserRepository; If you want this repository to be a Redis repository, consider annotating your entities with one of these annotations: org.springframework.data.redis.core.RedisHash (preferred), or consider extending one of the following types with your repository: org.springframework.data.keyvalue.repository.KeyValueRepository
2024-03-29T09:45:06.136Z  INFO 10 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 35 ms. Found 0 Redis repository interfaces.
2024-03-29T09:45:09.076Z DEBUG 10 --- [           main] liquibase.servicelocator                 : Loaded liquibase.command.CommandStep instance liquibase.command.core.helpers.DiffOutputControlCommandStep

[...]

2024-03-29T09:45:09.250Z DEBUG 10 --- [           main] liquibase.servicelocator                 : Loaded liquibase.precondition.Precondition instance liquibase.precondition.core.UniqueConstraintExistsPrecondition
2024-03-29T09:45:09.251Z DEBUG 10 --- [           main] liquibase.servicelocator                 : Loaded liquibase.precondition.Precondition instance liquibase.precondition.core.ViewExistsPrecondition
] as e92ed04a11a5e95df6ca69b32c49bd24
2024-03-29T09:45:10.347Z DEBUG 10 --- [           main] liquibase.util                           : Computed checksum for addForeignKeyConstraint:[
    baseColumnNames="botanical_info_id"
    baseTableName="synonyms"
    constraintName="fk_synonyms_botanicalInfo"
    onDelete="CASCADE"
    referencedColumnNames="id"
    referencedTableName="botanical_infos"
] as 159a4297034d4fb87c17a7f65fb696c3
2024-03-29T09:45:10.348Z DEBUG 10 --- [           main] liquibase.util                           : Computed checksum for dropForeignKeyConstraint:[
    baseTableName="reminders"
    constraintName="fk_reminder_plant"
] as 9a46e238c6a56248697ac95a563ee168
2024-03-29T09:45:10.348Z DEBUG 10 --- [           main] liquibase.util                           : Computed checksum for addForeignKeyConstraint:[
    baseColumnNames="target_id"
    baseTableName="reminders"
    constraintName="fk_reminder_plant"
    onDelete="CASCADE"
    referencedColumnNames="id"
    referencedTableName="plants"
] as 503023b47505ca7d2336b5f9222f316a
2024-03-29T09:45:10.348Z DEBUG 10 --- [           main] liquibase.util                           : Computed checksum for dropForeignKeyConstraint:[
    baseTableName="notification_dispatchers"
    constraintName="fk_dispatcher_user"
] as dd5cefb0862433a4b75128f2ba617400
2024-03-29T09:45:10.349Z DEBUG 10 --- [           main] liquibase.util                           : Computed checksum for addForeignKeyConstraint:[
    baseColumnNames="user_id"
    baseTableName="notification_dispatchers"
    constraintName="fk_dispatcher_user"
    onDelete="CASCADE"
    referencedColumnNames="id"
    referencedTableName="application_users"
] as 58b0434f363c4adba81a4026808f33f5
2024-03-29T09:45:10.349Z DEBUG 10 --- [           main] liquibase.util                           : Computed checksum for 9:bf745b912cb4d8fa59c3a40ec182954a:9:2f07d62e6fa954f04b2543acac340db0:9:a5b0708cbf1aaf26694d8ce75f5f1491:9:282884485e6260832d5311e65affef5e:9:1fdabafd20b0ab11531f1a9c9953196e:9:1555960f3509b000e456f869a0a961ac:9:c341f9b1015ca3d1cdbe3bec35514b6d:9:d5c7669b92606deae04a40c6deb96427:9:06ae287b04f773f001a540d019ae1699:9:25c1ff0efd955103e1df9d86d872851a:9:f3094f6af7cabd6913002a34ed39a387:9:5a4c7cb35d14bcecab4dd9b178f97bfe:9:8987a6221e0804cffd5103ed1376fa69:9:20d9f12e3b190721da780abe4bd192d7:9:0a6d8396... [truncated in log] as c634128019dacc068d1e76dcd2f952ec
2024-03-29T09:45:10.350Z DEBUG 10 --- [           main] liquibase.util                           : Computed checksum for addUniqueConstraint:[
    columnNames="creator, external_id"
    constraintName="botanical_info_external_id_unique"
    tableName="botanical_infos"
] as 30e3a9745fca032999e5bbc2b25428bc
2024-03-29T09:45:10.350Z DEBUG 10 --- [           main] liquibase.util                           : Computed checksum for 9:30e3a9745fca032999e5bbc2b25428bc: as edd5ef47cce94adb632f57b7a6ed3729
2024-03-29T09:45:10.351Z DEBUG 10 --- [           main] liquibase.util                           : Computed checksum for dropUniqueConstraint:[
    constraintName="botanical_info_scientific_name_unique"
    tableName="botanical_infos"
] as 7fbe67f0acf7671f1829522a25267e35
2024-03-29T09:45:10.352Z DEBUG 10 --- [           main] liquibase.util                           : Computed checksum for dropColumn:[
    columnName="scientific_name"
    tableName="botanical_infos"
] as 13279b23a2713c561dc5007686b0bb52
2024-03-29T09:45:10.352Z DEBUG 10 --- [           main] liquibase.util                           : Computed checksum for 9:7fbe67f0acf7671f1829522a25267e35:9:13279b23a2713c561dc5007686b0bb52: as 6da8bafd64f4706b1d6f1862de035593
2024-03-29T09:45:10.352Z DEBUG 10 --- [           main] liquibase.command                        : Executing internal command changeExecListener

[...]

2024-03-29T09:45:10.425Z DEBUG 10 --- [           main] liquibase.servicelocator                 : Loaded liquibase.datatype.LiquibaseDataType instance liquibase.datatype.core.DoubleDataTypeSnowflake
2024-03-29T09:45:10.425Z DEBUG 10 --- [           main] liquibase.servicelocator                 : Loaded liquibase.datatype.LiquibaseDataType instance liquibase.datatype.core.BinaryTypeSnowflake
2024-03-29T09:45:10.428Z DEBUG 10 --- [           main] liquibase.executor                       : Changelog query completed.
2024-03-29T09:45:10.429Z  INFO 10 --- [           main] liquibase.lockservice                    : Successfully released change log lock
2024-03-29T09:45:10.430Z  INFO 10 --- [           main] liquibase.command                        : Command execution complete
2024-03-29T09:45:11.027Z  INFO 10 --- [           main] SQL dialect                              : HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect
2024-03-29T09:45:12.952Z  INFO 10 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2024-03-29T09:45:13.881Z DEBUG 10 --- [           main] c.g.m.p.security.jwt.JwtTokenFilter      : Filter 'jwtTokenFilter' configured for use
2024-03-29T09:45:13.882Z DEBUG 10 --- [           main] c.g.m.p.security.apikey.ApiKeyFilter     : Filter 'apiKeyFilter' configured for use

After that, nothing happens.

And when I remove these lines :

SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_EMAIL=[email protected]
SMTP_PASSWORD=xxxx xxxx xxxx xxxx
SMTP_AUTH=true
SMTP_START_TTL=true
CONTACT_MAIL=[email protected]

the project starts working normally again.

Illegal character in fragment at index 62

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

I just installed the docker version of the app. After initially running into the missing backend issue because I unnecessarily changed the ports in frontend.env and backend.env .

After fixing that with the help of another thread here (#60), it seemed to be up and running.

I created my user account. And then I got the following error. I get this error message every time I log in.

Illegal character in fragment at index 62: https://trefle.io/api/v1/species/search?limit=5&page=1&token=# put you key here, otherwise the "search" feature will include only user generated species&q=*

I am pretty sure content is not loading that should be there. Probably the database of plants. I can hit the +, but anything I type into a field will be removed as soon as I click outside of the field again.
If I go to Search (I assume that is normally the database), and start searching, I get the error above again:

image

Sometimes it will reference index 66.

Expected behaviour

content to be available, specifically a database of plants. or to at least be able to add my own plants.

Steps to reproduce

No response

Local environment

docker compose

Additional info

No response

Backend always starts tomcat as https

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

The backend server always starts up tomcat in an https mode. When using http mode, the client always reports that the backend can not be reached.
I can reach both the frontend and backend when browsing to them individually, but when using http to connect to the backend server it displays a warning, that this connection is tls only.
I also tried the ssl_enabled=true mode, but it causes some issues in browsers that i cant tolerate.

Expected behaviour

The tomcat server is expected to run in an not https mode when setting the env varibale to ssl_enabled=false

Steps to reproduce

I just used the default example from the documentation and modified the paths and ports according to documentation.

Local environment

  1. Docker
  2. Compose.yaml:
version: "3"
name: plant-it
services:
  backend:
    image: msdeluise/plant-it-backend:latest
    env_file: backend.env
    depends_on:
      - db
      - cache
    restart: unless-stopped
    volumes:
      - "/pool/config/plantit/upload-dir:/upload-dir"
      - "/pool/config/plantit/certs:/certificates"
    ports:
      - "8089:8080"
  db:
    image: mysql:8.0
    restart: always
    env_file: backend.env
    volumes:
      - "/pool/config/plantit/db:/var/lib/mysql"
  cache:
    image: redis:7.2.1
    restart: always
  frontend:
    image: msdeluise/plant-it-frontend:latest
    env_file: frontend.env
    links:
      - backend
    ports:
      - "3009:3000"
    volumes:
      - "/pool/config/plantit/certs:/certificates"
  1. Backend.env
#
# DB
#
MYSQL_HOST=db
MYSQL_PORT=3306
MYSQL_USERNAME=root
MYSQL_PSW=root
MYSQL_ROOT_PASSWORD=root
MYSQL_DATABASE=bootdb

#
# JWT
#
JWT_SECRET=mfijekdkmvsfeqlkmqko51421551
JWT_EXP=1

#
# Server config
#
USERS_LIMIT=2
UPLOAD_DIR=/upload-dir
API_PORT=8080
TRAFLE_KEY=
ALLOWED_ORIGINS=*

#
# Cache
#
CACHE_TTL=86400
CACHE_HOST=cache
CACHE_PORT=6379

#
# SSL
#
SSL_ENABLED=false
CERTIFICATE_PATH=/certificates/

  1. Frontend.env
PORT=3000
API_URL=http://192.168.1.103:8089/api
WAIT_TIMEOUT=5000
PAGE_SIZE=25
BROWSER=none
SSL_ENABLED=false
CERTIFICATE_PATH=/certificates/

Additional info

Thanks for your work on this cool project.
Hope you can help, would be amazing to use your app!

Possibility to change thumbnail picture when plant added from search feature.

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

When I add a plant I found using the search feature, I can't edit the thumbnail picture.

It is possible when the plant is added as "custom" though.

Solution

Would be nice to use the search feature to use as a template and then edit the info including thumbnail.

What are alternatives?

No response

Additional context

From search function, maybe like in the "custom" window and as in this example :

plantit.jpg

Missing tests

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

Currently, tests are missing in the system.
For the backend, the test directory has already a files' template useful to create unit and integration test.

Solution

Add unit and integration tests.

What are alternatives?

No response

Additional context

No response

Option for maximum width

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

Please consider adding an option for max width on desktop, to make the page more pleasant to use on wide screens.

Solution

Similar options to what Monica 4.x provides:
image

What are alternatives?

No response

Additional context

No response

Add description to images

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

It would be useful to have the possibility of writing a description for the uploaded images.

Solution

No response

What are alternatives?

No response

Additional context

No response

Add common names for custom created species

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

Similar to the Trefle service, a user-created species should include a scientific_name along with optional synonyms and common_names fields.
This enhancement becomes particularly beneficial in scenarios where a user modifies the Trefle species, such as changing the thumbnail.
For example, currently a new custom species for Helianthus annuus is generated when the user makes modifications. Consequently, when searching for sunflower, only the Trefle species is provided.
This limitation exists because users must search precisely for Helianthus annuus to find their custom species.
The inclusion of a common_names field for user-created species would alleviate this issue.

Solution

Add a field called common_names (or synonyms) to the species object and use this along the scientific_name when searching.

What are alternatives?

No response

Additional context

No response

Typo in `TRAFLE_KEY` parameter

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

The TRAFLE_KEY parameter should be named TREFLE_KEY since the service that use that key is called trefle and not trafle.

Expected behaviour

No response

Steps to reproduce

No response

Additional info

It has to be chosen if create a breaking change with the previous commits or if achieve this in a backward compatible manner (maybe creating 2 parameters with the same name?)

Missing tests

Discussed in #91

Originally posted by MDeLuise September 5, 2023

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

Currently, tests are missing in the system.
For the backend, the test directory has already a files' template useful to create unit and integration test.

Solution

Add unit and integration tests.

What are alternatives?

No response

Additional context

No response

Searching for plant returns error

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

I go to the plant, search and I get the following error returned :
Cannot invoke "com.google.gson.JsonElement.getAsJsonArray()" because the return value of "com.google.gson.JsonObject.get(String)" is null"

Expected behaviour

No response

Steps to reproduce

No response

Additional info

TabTip_x4ynIqNmQI

Retrieving Account Information

Question

One of my family members forgot the password for her account. Is there a way to reset the password or find her account info in the database?

Backend tests are missing

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

Currently, tests are missing in the system.
This issue is to track the tests on the backend side.
For this side, the test directory has already a files' template useful to create unit and integration tests.

Solution

Add unit and integration tests.

What are alternatives?

No response

Additional context

No response

Translations

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

IS a good idea translate app yo another languages.
If you tell me how can i help you, i can translate It to Spanish.

Thank for this really good app

Solution

No response

What are alternatives?

No response

Additional context

No response

Add SSL support

Discussed in #102

Originally posted by MDeLuise February 6, 2024

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

It would be great to have the possibility of using SSL for deploying the app.

Solution

No response

What are alternatives?

No response

Additional context

I think SSL is also mandatory for using service workers, i.e. for example for using a "cached version" of the app when offline.

Uploaded image creation date

Discussed in #99

Originally posted by MDeLuise February 6, 2024

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

It would be great to set the correct creation date for the uploaded images.
Right now, every image has the "creation date" as the day of upload, but it would be great to have it as effectively creation date.
It would be also useful to have the possibility of changing that value over time.

Solution

No response

What are alternatives?

No response

Additional context

No response

Add more info sources

Discussed in #90

Originally posted by MDeLuise December 19, 2023

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

It would be useful to enhance the app by incorporating additional information sources. This not only provides users with more comprehensive data but also serves as a backup in the event that the Trefle API service becomes unavailable or the user does not have access to network.

Solution

During initial exploration, I came across this service as a potential information source for plants. Notably, the database can be downloaded in CSV format from here. A feasible approach would be to parse this file during the app's startup, allowing for the storage of all species contained within it in the app's database.

What are alternatives?

Other services could be used, if you find any please add them in this conversation.

Additional context

Currently, the app uses only Trefle species and "local" species. Consequently, when searching for a species, the user is presented with a maximum of two choices for the same species. To accommodate the expansion of services for retrieving species information, a decision must be made regarding the handling of duplicated species. One approach is to offer only the most detailed entry to the user. Alternatively, all duplicated species from the employed services could be provided, each species tagged by service — using labels such as "Trefle," "Custom," "USDA," and so on.

Adding plant from Trefle without thumbnail results in TypeError

Avoid duplicated bug reports

  • I've found a bug and checked that there are no open or closed bug report related to this.

Description

While trying to add a plant using search on Trefle feature while said plant does not have a thumbnail -- nothing happens on UI and I get this error in console: TypeError: Failed to execute 'readAsArrayBuffer' on 'FileReader': parameter 1 is not of type 'Blob'.

It could

Expected behaviour

Plant should be added even without the thumbnail

Steps to reproduce

  1. Go to the species (search icon) tab
  2. Search for "Raphanus raphanistrum subsp. sativus"
  3. Select the "Raphanus raphanistrum subsp. sativus" result from Trefle
  4. Try to save the plant

The same is true for some other thumbnailless plants, for example "Petroselinum crispum subsp. giganteum" or "Polyscias muraltana"

Local environment

Docker, 0.4.3

Additional info

Here's the full error:

AddPlant.tsx:789 Uncaught (in promise) TypeError: Failed to execute 'readAsArrayBuffer' on 'FileReader': parameter 1 is not of type 'Blob'.
    at AddPlant.tsx:789:20
    at new Promise (<anonymous>)
    at v (AddPlant.tsx:776:9)
    at AddPlant.tsx:757:17
    at new Promise (<anonymous>)
    at g (AddPlant.tsx:738:16)
    at AddPlant.tsx:696:21
(anonymous) @ AddPlant.tsx:789
v @ AddPlant.tsx:776
(anonymous) @ AddPlant.tsx:757
g @ AddPlant.tsx:738
(anonymous) @ AddPlant.tsx:696
Promise.then (async)
(anonymous) @ AddPlant.tsx:758
g @ AddPlant.tsx:738
(anonymous) @ AddPlant.tsx:696
Promise.then (async)
onClick @ AddPlant.tsx:682
Le @ react-dom.production.min.js:54
Ve @ react-dom.production.min.js:54
(anonymous) @ react-dom.production.min.js:55
zr @ react-dom.production.min.js:105
Fr @ react-dom.production.min.js:106
(anonymous) @ react-dom.production.min.js:117
uc @ react-dom.production.min.js:274
je @ react-dom.production.min.js:52
Ur @ react-dom.production.min.js:109
Gt @ react-dom.production.min.js:74
qt @ react-dom.production.min.js:73

Easy way to change ports, either by .env files or in guide

Avoid duplicated feature requests

  • There are no open or closed feature requests that are related to this request

Description

  • Easy way to change active ports, either by .env files or in guide. As I can see, only the nginx proxy is port-interchangeable due to the other links being hardcoded, which I have found doesn't really work for me when both port 8080 and port 3000 is in use by other systems.

Solution

Making ports changeable in .env files

What are alternatives?

No response

Additional context

No response

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.